創建型模式
- 單例模式
- 工廠模式
- 建造者模式
- 原型模式
- 對象池模式
工廠模式
所謂工廠,我們可以理解爲一個用來生產實例的工具,工廠負責生產一系列同一性質的產品。在調用的時候,我們把這個工廠看做一個黑盒,我們只要告訴它我們需要什麼實例,他就會給我們創建對應的實例。
1. 靜態工廠模式
我們寫一個簡單地工廠類來創建Vehicle實例。我們創建一個抽象Vehicle類和繼承自它的三個具體類:Bike、Car和Truck。 工廠類(也叫做靜態工廠類),代碼如下:
public class VehicleFactory{
//用來讓開發者選擇需要創建的對象的標誌
public enum VehicleType{
Bike,
Car,
Truck;
}
public static Vehicle create(VehicleType type){
if(type.equals(Vehicle.Bike) return new Bike();
if(type.equals(Vehicle.Car) return new Car();
if(type.equals(Vehicle.Truck) return new Truck();
else return null;//這個else針對的是最後一個if
}
}
這個靜態工廠類邏輯簡單,有好的地方:它只負責Vehicle類的實例化,符合單一職責原則,用戶只需要調用Vehicle接口,符合了依賴倒置原則。但是不能很好的適應市場環境,真實開發過程中,可能會增加新的Vehicle類,這時候每增加一個Vehicle類就要對該VehicleFactory進行一次修改,這就違反了開閉原則(已經寫好的類最好不要進行修改,只進行拓展)
所以我們需要對其進行修改,另其符合開閉原則,實現方法有下面兩種:
- 適用反射機制註冊產品類對象和實例化
- 註冊產品對象並向每個產品添加newInstance()方法,該方法返回與自身類型相同的新實例。
1.1 使用反射機制進行類註冊的簡單工廠模式
爲此,我們需要使用map對象來保存產品ID以及它對應的類
private Map<String,Class> registerdProducts = new HashMap<String,Class>();
然後,增加一個註冊新Vehicle類的方法:
public void registerVehicle(String vehicleId,Class vehicleClass){
registerdProducts.put(vehicleId,vehicleClass);
}
構造方法如下:
public Vehicle createVehicle(String type) throws InstantiationException,IllegalAccessException{
Class productClass = registerdProducts.get(type);
return (Vehicle) productClass.newInstance();
}
我們知道,使用反射會使得程序運行效率降低,有的情況下,反射機制並不適用,比如反射機制需要運行時權限,這導致有的特定環境下,反射獲得實例無法實現。
在對性能要求很高的場景下,應該儘量避免使用這種機制。
1.2 使用newInstance方法進行類註冊的簡單工廠模式
每個產品類都可以創建自己的實例
首先在Vehicle基類中添加一個抽象方法:
abstract public Vehicle newInstance();
對於每種產品,基類(父類)聲明爲抽象的方法都要實現
@Override
public Car newInstance(){
return new Car();
}
在工廠類中,更改map用於保存對象的ID以及它對應的Vehicle對象
private Map<String,Vehicle> registerdProducts = new HashMap<String,Vehicle>();
通過實例註冊一種新的Vehicle類型:
public void registerVehicle(Sring vehicleId, Vehicle vehicle){
registerdProducts.put(vehicleId,vehicle);
}
也要對應地改變Factory中的createVehicle方法:
public Vehicle createVehicle(String vehicleId){
return registerdProducts.get(vehicleId).newInstance();
}
調用方法:
public class test{
public static void main(String[] args){
registerVehicles();
//動態註冊以後,就可以隨時讓工廠生產該實例
Car car = (Car)VehicleFactory.createVehicle("Car");
}
pulic static void registerVehicles(){
VehicleFactory.registerVehicle("Car",new Car());
VehicleFactory.registerVehicle("Truck",new Truck());
}
}
2. 工廠方法模式
工廠方法模式是在靜態工廠模式上的改進。工廠類被抽象化,使用實例化特定產品類的代碼被轉移到實現抽象方法的子類中。這樣不需要修改就可以拓展工廠類。
我們在抽象工廠類中不實現具體的實例化代碼,而是交給抽象工廠類的實現類來完成,這樣如果要拓展更多種實例,就只需要添加抽象工廠類的新實現,而不需要修改它,符合開閉原則。
比如我們有一個汽車工廠,目前只有兩種車型,小型跑車和大型家用車,在軟件中,顧客可以自由決定買什麼樣的車,首先小型車對應的Vehicle類的子類爲SportCar,大型家用車對應的Vehicle子類爲SedanCar。
創建Vehicle類結構之後就可以創建抽象工廠類。注意工廠類中沒有創建實例的代碼。
public abstract class VehicleFactory{
//只允許子類訪問,對外界隱藏,創建Vehicle,傳入對應size參數
protected abstract Vehicle createVehicle(String size);
public Vehicle orderVehicle(String size, String color){
Vehicle vehicle = createVehicle(size);
vehicle.setColor(color);
return vehicle;
}
}
爲了增加汽車實例化的代碼,我們創建了VehicleFactory的子類,也就是CarFactory類,並且在CarFactory中實現從父類中調用的createVehicle抽象方法。實際上,我們可以理解爲,VehicleFactory是一個總公司,它將具體的實例化需求委託給了分工廠。
public class CarFactory extends VehicleFactory{
@Override
protected Vehicle createVehicle(String size){
if(size.equals("small") return new SportCar();
else if(size.equals("big") return new SedanCar();
return null;
}
}
如此一來,在客戶端,我們只需要創建工廠類並創建訂單就可以了
VehicleFactory carFactory = new CarFactory();
carFactory.orderVehicle("big","blue");
如果我們另外增加了業務,比如還需要生產卡車,那我們就創建一個卡車工廠TruckFactory,負責卡車的實例化操作。
public class TruckFactory extends VehicleFactory{
@Override
protected Vehicle createVehicle(String size){
if(size.equals("small")) return SmallTruck();
else if(size.equals("big") return BigTruck();
return null;
}
}
調用手段一致
VehicleFactory truckFactory = new TruckFactory();
truckFactory.orderVehicle("small");
如果說業務量很少,那麼我們不需要新建一個類來作爲大工廠,只需要一個臨時工廠,這裏我們通過匿名具體工廠模式來實現。
Vehicle Factory tempFactory = new VehicleFactory(){
@Override
protected Vehicle createVehicle(String size){
if(size.equals("small") return new SmallTempCar();
else if(size.equals("big") return new BigTempCar();
return null;
}
}
tmepFactory.orderVehicle("big","blue");
3. 抽象工廠模式
抽象工廠模式是工廠方法模式的擴展版本,它不再時創建單一類型的對象,而是創建一系列相關聯的對象。如果說工廠方法模式中只包含一個抽象產品類,那麼抽象工廠模式則包含多個抽象產品類。
注意到,抽象工廠模式是創建一系列相關聯的對象。
比如題庫工廠,語文方面有語文課本,語文天天練練習冊,語文筆記本,語文單元卷,這是一系列相關聯的對象,對應的英語方面,也有英語課本,英語天天練練習冊,英語筆記本,英語單元卷。
用於實例化一系列相關聯類的工廠繼承自抽象工廠。
我們有抽象工廠類,規範了我們要創建對象的方法
public abstract class AbstractFactory{
public AbstractTextBook createTextBook();
public AbstractExerciseBook createExerciseBook();
public AbstractNoteBook createNoteBook();
public AbstractTestPaper createTestPaper();
}
接下來比如我們的目標是語文工廠,那麼我們先定一下語文的相關類
CNTextBook類、CNExerciseBook類、CNNoteBook類、CNTestPaper類。
然後新建一個語文工廠負責創建該系列類
public class CNFactory extends AbstractFactory{
@Override
public AbstractTextBook createTextBook(){
return new CNTextBook();
}
@Override
public AbstractExerciseBook createExerciseBook(){
return new CNExerciseBook();
}
@Override
public AbstractNoteBook createNoteBook(){
return new CNNoteBook();
}
@Override
public AbstractTestPaper createTestPaper(){
return new CNTestPaper();
}
}
參考:
《Java設計模式及實踐》