工廠模式划分來說總共有三類:簡單工廠模式、工廠方法模式和抽象工廠模式。其中簡單工廠模式不輸入23種設計模式之一,但他們又都屬於創建型
模式。我們依次講解這三種工廠模式。
一、簡單工廠
1、什么是簡單工廠模式?
首先來說簡單工廠,簡單工廠模式,又叫做靜態工廠模式(Static Factory Method),由一個工廠對象決定創建出哪一種產品類的實例,簡單工廠模式的實質是由一個工廠類根據傳入的參數,動態決定應該創建哪一個產品類。屬於創建型
模式,但不屬於GOF23設計模式。
2、簡單工廠適用場景
工廠類負責創建的對象比較少;客戶端(應用層)只需要知道傳入工廠類的參數,對於如何創建對象(邏輯)不關心。
3、簡單工廠優缺點
- 優點:只需要傳入一個正確的參數,就可以獲取你所需要的對象,而無需知道其細節創建。
- 缺點:工廠類的職責相對過重,增加新的產品,需要修改工廠類的判斷邏輯,違背了開閉原則。
4、簡單工廠實現
首先來看類圖:
代碼實現:
public class ShapeFactory { public Shape getShape(String shapeType){ if(shapeType.equalsIgnoreCase("circle")){ return new Circle(); }else if(shapeType.equalsIgnoreCase("rectangle")){ return new Rectangle(); }else if(shapeType.equalsIgnoreCase("squere")){ return new Squere(); } return null; } public Shape getShape(Class clazz) throws Exception{ return (Shape) clazz.newInstance(); } }
二、工廠方法模式
1、什么是工廠方法
工廠方法模式(Factory Method),又稱多態性工廠模式,屬於設計模式三大分類中的創建型模式
,作為抽象工廠模式的孿生兄弟,工廠方法模式定義了一個創建對象的接口,但由子類決定要實例化的類是哪一個,也就是說工廠模式讓實例化推遲到子類。如類圖所示:
在工廠模式中,核心的工廠類不再負責所有的產品的創建,而是將具體的工作交給子類去做。該核心類成為一個抽象工廠角色,僅負責給出具體工廠子類必須實現的接口,而不接觸哪一個產品應當被實例化這種細節。
2、工廠方法優缺點
- 優點:用戶只需要關系所需產品對應的工廠,無須關心創建細節;加入新產品符合開閉原則,提高可擴展性。
- 缺點:類的個數容易過多,增加復雜度;增加了系統的抽象性和理解難度。
工廠方法模式非常符合“開閉原則”,當需要增加一個新產品時,我們只需要增加一個具體的產品類和與之對應的具體工廠即可,無須關系產品的創建過程,甚至連具體的產品類名稱都不需要知道。雖然他很好的符合了“開閉原則”,但是由於每新增一個新產品時就需要增加兩個類,這樣勢必就會導致系統的復雜度增加。
3、代碼實現
public interface Shape { void draw(); } public class Circle implements Shape { @Override public void draw() { System.out.println("畫一個圓"); } } public class Rectangle implements Shape { @Override public void draw() { System.out.println("畫一個矩形"); } }
代碼(工廠部分):
public abstract class ShapeFactory { public abstract Shape getShape(); } public class CircleFactory extends ShapeFactory { @Override public Shape getShape() { return new Circle(); } } public class RectangleFactroy extends ShapeFactory { @Override public Shape getShape() { return new Rectangle(); } }
4、工廠方法模式的應用場景
工廠方法模式通常適用於以下場景。
- 客戶只知道創建產品的工廠名,而不知道具體的產品名。如 TCL 電視工廠、海信電視工廠等。
- 創建對象的任務由多個具體子工廠中的某一個完成,而抽象工廠只提供創建產品的接口。
- 客戶不關心創建產品的細節,只關心產品的品牌。
5、工廠方法模式的擴展
當需要生成的產品不多且不會增加,一個具體工廠類就可以完成任務時,可刪除抽象工廠類。這時工廠方法模式將退化到簡單工廠模式,其結構圖如圖所示:
三、抽象工廠模式
1、什么是抽象工廠模式
抽象工廠(AbstractFactory)模式的定義:是一種為訪問類提供一個創建一組相關或相互依賴對象的接口,且訪問類無須指定所要產品的具體類就能得到同族的不同等級的產品的模式結構。抽象工廠模式是工廠方法模式的升級版本,工廠方法模式只生產一個等級的產品,而抽象工廠模式可生產多個等級的產品。
2、抽象工廠使用條件
使用抽象工廠模式一般要滿足以下條件。
- 系統中有多個產品族,每個具體工廠創建同一族但屬於不同等級結構的產品。
- 系統一次只可能消費其中某一族產品,即同族的產品一起使用。
3、優缺點
- 優點:具體產品在應用層代碼隔離,無須關心創建細節;將一個系列的產品族統一到一起創建。
- 缺點:規定了所有可能被創建的產品集合,產品族中擴展新的產品困難,需要修改抽象工廠的接口;增加了系統的抽象性和理解難度
4、抽象工廠模式實現
抽象工廠模式的主要角色如下。
- 抽象工廠(Abstract Factory):提供了創建產品的接口,它包含多個創建產品的方法 newProduct(),可以創建多個不同等級的產品。
- 具體工廠(Concrete Factory):主要是實現抽象工廠中的多個抽象方法,完成具體產品的創建。
- 抽象產品(Product):定義了產品的規范,描述了產品的主要特性和功能,抽象工廠模式有多個抽象產品。
- 具體產品(ConcreteProduct):實現了抽象產品角色所定義的接口,由具體工廠來創建,它 同具體工廠之間是多對一的關系。
抽象工廠模式結構圖如圖所示:
以華為、小米2個品牌,分別生產手機、路由器為例,代碼如下(產品類別接口以及對應工廠接口):
/** * 手機產品接口 */ public interface IPhoneProduct { /** * 開機 */ void start(); /** * 關機 */ void shutdown(); /** * 撥打電話 */ void callUp(); /** * 發送短信 */ void sendSMS(); } /** * 路由器產品接口 */ public interface IRouterProduct { /** * 開機 */ void start(); /** * 關機 */ void shutdown(); /** * 開啟wifi */ void openWifi(); /** * 設置參數 */ void setting(); } /** * 抽象產品工廠(定義了同一個產品族的產品生產行為) */ public interface IProductFactory { /** * 生產手機 * @return */ IPhoneProduct produceTelPhone(); /** * 生產路由器 * @return */ IRouterProduct produceRouter(); }
接下來看產品類:
/** * 華為手機產品 */ public class HuaweiPhone implements IPhoneProduct { @Override public void start() { System.out.println("開啟華為手機"); } @Override public void shutdown() { System.out.println("關閉華為手機"); } @Override public void callUp() { System.out.println("用華為手機打電話"); } @Override public void sendSMS() { System.out.println("用華為手機發短信"); } } /** * 華為路由器產品 */ public class HuaweiRouter implements IRouterProduct { @Override public void start() { System.out.println("啟動華為路由器"); } @Override public void shutdown() { System.out.println("關閉華為路由器"); } @Override public void openWifi() { System.out.println("打開華為路由器的wifi功能"); } @Override public void setting() { System.out.println("設置華為路由器參數"); } } /** * 小米手機產品 */ public class XiaomiPhone implements IPhoneProduct { @Override public void start() { System.out.println("開啟小米手機"); } @Override public void shutdown() { System.out.println("關閉小米手機"); } @Override public void callUp() { System.out.println("用小米手機打電話"); } @Override public void sendSMS() { System.out.println("用小米手機發短信"); } } /** * 小米路由器產品 */ public class XiaomiRouter implements IRouterProduct { @Override public void start() { System.out.println("啟動小米路由器"); } @Override public void shutdown() { System.out.println("關閉小米路由器"); } @Override public void openWifi() { System.out.println("打開小米路由器的wifi功能"); } @Override public void setting() { System.out.println("設置小米路由器參數"); } }
最后看產品工廠:
/** * 華為產品工廠 */ public class HuaweiProductFactory implements IProductFactory{ @Override public IPhoneProduct produceTelPhone() { System.out.println(">>>>>>生產華為手機"); return new HuaweiPhone(); } @Override public IRouterProduct produceRouter() { System.out.println(">>>>>>生產華為路由器"); return new HuaweiRouter(); } @Override public IComputer produceComput() { return null; } } /** * 小米產品工廠 */ public class XiaomiProductFactory implements IProductFactory { @Override public IPhoneProduct produceTelPhone() { System.out.println(">>>>>>生產小米手機"); return new XiaomiPhone(); } @Override public IRouterProduct produceRouter() { System.out.println(">>>>>>生產小米路由器"); return new XiaomiRouter(); } @Override public IComputer produceComput() { return null; } }
測試類如下:
/** * 使用 FactoryProducer 來獲取 AbstractFactory,通過傳遞類型信息來獲取實體類的對象。 */ public class Test { public static void main(String[] args) { System.out.println("===================小米系列產品================="); //小米產品工廠實例 IProductFactory xiaomiProductFactory = new XiaomiProductFactory(); //生產小米路由器 IRouterProduct xiaomiRouter = xiaomiProductFactory.produceRouter(); xiaomiRouter.start(); xiaomiRouter.setting(); xiaomiRouter.openWifi(); xiaomiRouter.shutdown(); //生產小米手機 IPhoneProduct xiaomiPhone = xiaomiProductFactory.produceTelPhone(); xiaomiPhone.start(); xiaomiPhone.callUp(); xiaomiPhone.sendSMS(); xiaomiPhone.shutdown(); System.out.println("===================華為系列產品================="); //華為產品工廠實例 IProductFactory huaweiProductFactory = new HuaweiProductFactory(); //生產華為路由器 IRouterProduct huaweiRouter = huaweiProductFactory.produceRouter(); huaweiRouter.start(); huaweiRouter.setting(); huaweiRouter.openWifi(); huaweiRouter.shutdown(); //生產華為手機 IPhoneProduct huaweiPhone = huaweiProductFactory.produceTelPhone(); huaweiPhone.start(); huaweiPhone.callUp(); huaweiPhone.sendSMS(); huaweiPhone.shutdown(); } }
測試結果如下:
===================小米系列產品================= >>>>>>生產小米路由器 啟動小米路由器 設置小米路由器參數 打開小米路由器的wifi功能 關閉小米路由器 >>>>>>生產小米手機 開啟小米手機 用小米手機打電話 用小米手機發短信 關閉小米手機 ===================華為系列產品================= >>>>>>生產華為路由器 啟動華為路由器 設置華為路由器參數 打開華為路由器的wifi功能 關閉華為路由器 >>>>>>生產華為手機 開啟華為手機 用華為手機打電話 用華為手機發短信 關閉華為手機
5、抽象工廠模式的應用場景
抽象工廠模式最早的應用是用於創建屬於不同操作系統的視窗構件。如 java 的 AWT 中的 Button 和 Text 等構件在 Windows 和 UNIX 中的本地實現是不同的。
抽象工廠模式通常適用於以下場景:
- 當需要創建的對象是一系列相互關聯或相互依賴的產品族時,如電器工廠中的電視機、洗衣機、空調等。
- 系統中有多個產品族,但每次只使用其中的某一族產品。如有人只喜歡穿某一個品牌的衣服和鞋。
- 系統中提供了產品的類庫,且所有產品的接口相同,客戶端不依賴產品實例的創建細節和內部結構。
6、抽象工廠模式的擴展
抽象工廠模式的擴展有一定的“開閉原則”傾斜性:
- 當增加一個新的產品族時只需增加一個新的具體工廠,不需要修改原代碼,滿足開閉原則。
- 當產品族中需要增加一個新種類的產品時,則所有的工廠類都需要進行修改,不滿足開閉原則。
另一方面,當系統中只存在一個等級結構的產品時,抽象工廠模式將退化到工廠方法模式。