一、工廠模式簡介
工廠是通常用來批量生產貨物的建築,通過工廠生產的貨物往往可以批量生產同樣的貨物。
在軟件開發中,如果需要創建對象時可以將對象當作是產品,將創建產品的對象叫做工廠。這樣就可以將創建對象和使用對象之間進行解耦,對象引用者無需關係對象是如何創建的,而工廠又可以保證創建出來的對象是一樣的。
工廠模式的定義:定義一個創建對象的工廠接口,將產品對象的實際創建工作交給工廠類或工廠類的子類中實現。
按照實際業務場景可以將工廠模式分爲三種模式:簡單工廠模式、工廠方法模式和抽象工廠模式,其中工廠方法模式和抽象工廠模式都是GoF設計模式中的一種
二、簡單工廠模式
當創建的產品類型是已知且有限的情況下,往往只需要一個工廠類就可以完成,此時就是簡單工廠模式。
簡單工廠模式有一個具體的工廠類,可以創建不同類型的產品,通常會提供一個靜態獲取對象的方法,根據傳入的參數創建指定類型的對象,所以也可以叫做靜態工廠方法模式。
簡單工廠模式雖然實現簡單,但是擴展性不強,每增加一個產品類型就需要增加一個具體的產品類和修改對應的具體工廠類,擴展成本較大,且違背了開閉原則
2.2、簡單工廠模式的角色
簡單工廠:負責創建所有產品的類
抽象對象:簡單工廠創建的所有對象的抽象,可以是抽象父類也可以是接口
具體產品:簡單工廠創建的具體對象類型
2.2、簡單工廠模式案例
汽車工廠可以創建不同品牌汽車,此時可以定義一個創建汽車的工廠,根據傳入的汽車品牌,創建不同品牌的汽車對象
代碼實現:
定義汽車抽象類
1 /** 2 * 汽車接口 3 */ 4 public interface Car { 5 6 public void showCarBrand(); 7 8 }
定義具體品牌的汽車類
1 /** 2 * 奔馳車產品類 3 */ 4 public class BenzCar implements Car{ 5 @Override 6 public void showCarBrand() { 7 System.out.println("我是一輛奔馳車"); 8 } 9 }
1 /** 2 * 寶馬車產品類型 3 */ 4 public class BmwCar implements Car{ 5 @Override 6 public void showCarBrand() { 7 System.out.println("我是一輛寶馬車"); 8 } 9 }
1 /** 2 * 奧迪車產品類 3 */ 4 public class AudiCar implements Car{ 5 6 @Override 7 public void showCarBrand() { 8 System.out.println("我是一輛奧迪車"); 9 } 10 }
定義汽車工廠類
1 /** 2 * 創建汽車產品的工廠類 3 */ 4 public class CarFactory { 5 6 public static Car getCar(String brand){ 7 Car car = null; 8 switch (brand){ 9 case "benz": 10 car = new BenzCar(); 11 break; 12 case "bmw": 13 car = new BmwCar(); 14 break; 15 case "audi": 16 car = new AudiCar(); 17 break; 18 default: 19 System.out.println("未知品牌"); 20 break; 21 } 22 return car; 23 } 24 }
測試代碼:
1 public static void main(String[] args) throws CloneNotSupportedException { 2 Car benz = CarFactory.getCar("benz"); 3 Car audi = CarFactory.getCar("audi"); 4 benz.showCarBrand(); 5 audi.showCarBrand(); 6 }
1 我是一輛奔馳車 2 我是一輛奧迪車
對於調用方而言無需關心具體的汽車產品是如何創建的,只需要從工廠中獲取指定類型的具體對象即可,這樣引用者類和具體產品類之間就實現瞭解耦,遵循了設計模式中的迪米特法則。
三、工廠方法模式
簡單工廠模式雖然簡單,但是擴展性較差,違背了開閉原則,而工廠方法模式就是對簡單工廠模式的進一步抽象,可以實現不修改工廠的情況下可以擴展創建更多類型的產品,即滿足了開閉原則
簡單工廠模式中創建對象是由工廠本身來實現,而工廠方法模式中工廠只負責提供具體產品的工廠對象,而並不直接創建產品。
3.1、工廠方法模式中的角色
抽象工廠:提供創建產品的抽象,調用者通過抽象訪問具體工廠的工廠方法來創建對象
具體工廠:實現抽象工廠的抽象方法,完成具體產品的創建
抽象對象:簡單工廠創建的所有對象的抽象,可以是抽象父類也可以是接口
具體產品:簡單工廠創建的具體對象類型
3.2、工廠方法模式案例
汽車工廠越做越大,不同類型汽車的製造越來越專業化,於是將不同品牌的汽車製造分別單獨建廠製造,而總工廠負責給各個具體的子工廠提供基礎規範
代碼實現:
在3.1的案例代碼基礎之上修改CarFactory,定義爲抽象接口,並定義一個創建汽車產品的方法
1 /** 2 * 創建汽車產品的工廠接口 3 */ 4 public interface CarFactory { 5 6 /** 定義獲取汽車產品的方法 */ 7 public Car getCar(); 8 }
分別定義具體生產汽車的工廠類實現抽象工廠接口
1 public class BenzCarFactory implements CarFactory{ 2 3 @Override 4 public Car getCar() { 5 System.out.println("奔馳工廠創建奔馳汽車"); 6 return new BenzCar(); 7 } 8 }
1 public class AudiCarFactory implements CarFactory{ 2 @Override 3 public Car getCar() { 4 System.out.println("奧迪汽車生產奧迪汽車"); 5 return new AudiCar(); 6 } 7 }
測試代碼:
1 public static void main(String[] args) throws CloneNotSupportedException { 2 CarFactory carFactory = new BenzCarFactory(); 3 Car benz = carFactory.getCar(); 4 benz.showCarBrand(); 5 }
1 奔馳工廠創建奔馳汽車 2 我是一輛奔馳車
相比於簡單工廠模式,工廠方法模式的擴展性更好,如果需要添加新的汽車品牌,只需要新增一個具體工廠實現抽象工廠接口即可,抽象工廠的定義不需要修改,從而實現對開閉原則的滿足。
四、抽象工廠模式
抽象工廠模式的定義是一種爲訪問類提供一個創建一組相關或相互依賴對象的接口,且訪問類無需指定所要產品的具體類就能夠得到同族的不同等級的產品的模式結構。
在工廠方法模式中,每一個具體的工廠類只可以創建同一種類型,比如奧迪工廠只能生產奧迪汽車,奔馳工廠只能生產奔馳汽車。但現實中工廠通常不會只生產一種產品,而是會生產多種種類的產品。比如奔馳工廠除了造奔馳轎車之外還可以生產跑車和商務車。
抽象工廠模式是工廠方法模式的升級版本,工廠方法模式只提供生產一種產品的工廠,而抽象工廠模式可以提供生產多個種類的產品。
抽象工廠模式優缺點:
1、可以在類的內部對產品族中相關聯的多等級產品共同管理,不必要引入多個新的類進行管理
2、抽象工廠增強了程序的可擴展性,增加一個新的產品族時,不需要修改原代碼,滿足開閉原則
3、當產品族添加新產品時,所有的工廠類都需要進行修改,比較難以抽象和理解
4.1、抽象工廠模式的角色
抽象工廠:提供創建產品的接口,包含多個創建產品的方法,可以創建多個不同的產品
具體工廠:實現抽象工廠的多個抽象方法,完成具體產品的創建
抽象對象:簡單工廠創建的所有對象的抽象,可以是抽象父類也可以是接口
具體產品:簡單工廠創建的具體對象類型
可以發現抽象工廠模式和工廠方法模式中的角色基本上差不多,不同的是抽象工廠不止定義了一個產品的創建方法,而是定義了多個產品的創建產品的方法定義,而具體的工廠也需要實現多個產品創建的方法
4.2、抽象工廠模式案例
不同的汽車工廠除了生產汽車之外,又額外擴展了其他的產品,比如奔馳工廠還可以奔馳的發動機,奧迪工廠可以生產奧迪的發動機
代碼實現:
定義發動機產品接口
1 /** 2 * 定義發動機型號 3 */ 4 public interface Engine { 5 public void showEngineBrand(); 6 }
定義發動機接口實現類,如奔馳發動機
1 public class BenzEngine implements Engine{ 2 @Override 3 public void showEngineBrand() { 4 System.out.println("我是奔馳的發動機"); 5 } 6 }
在3.2案例代碼的基礎上修改抽象工廠類,不僅可以生產汽車還可以生產發動機
1 /** 2 * 創建汽車產品族的工廠接口 3 */ 4 public interface CarFactory { 5 6 /** 定義獲取汽車產品的方法 */ 7 public Car getCar(); 8 9 /** 定義獲取發動機的方法 */ 10 public Engine getEngine(); 11 }
具體產品工廠實現抽象工廠,如奔馳工廠需要創建奔馳汽車和奔馳發動機
1 public class BenzCarFactory implements CarFactory{ 2 3 @Override 4 public Car getCar() { 5 System.out.println("奔馳工廠創建奔馳汽車"); 6 return new BenzCar(); 7 } 8 9 @Override 10 public Engine getEngine() { 11 System.out.println("奔馳工廠創建奔馳發動機"); 12 return new BenzEngine(); 13 } 14 }
測試代碼:
1 public static void main(String[] args) throws CloneNotSupportedException { 2 CarFactory carFactory = new BenzCarFactory(); 3 Car benz = carFactory.getCar(); 4 Engine engine = carFactory.getEngine(); 5 benz.showCarBrand(); 6 engine.showEngineBrand(); 7 }
1 奔馳工廠創建奔馳汽車 2 奔馳工廠創建奔馳發動機 3 我是一輛奔馳車 4 我是一個奔馳發動機
可以看出抽象工廠模式相對於工廠方法模式而言豐富了工廠的產品種類,避免了爲不同的產品創建不同的工廠,而是將相同族羣的產品交給同一個工廠來創建,降低了類的數量也降低了複雜度
不過抽象工廠並非優於工廠方法模式,主要看後期的業務擴展需要。
1、當業務擴展需要新增一個具體的工廠時,比如從奔馳工廠擴展添加奧迪工廠、保時捷工廠時,則不需要修改抽象工廠,滿足開閉原則
2、當業務擴展需要新增一個具體的產品時,比如奔馳工廠從生產汽車擴添加生產發動機、生產車輪、生產油箱時,則需要修改抽象工廠,且可能會影響其他的具體工廠,此時則不滿足開閉原則
所以具體業務場景該使用哪一種工廠模式需要看後期的業務擴展需求,但是應該儘量滿足開閉原則即可。