java設計模式-抽象工廠模式
抽象工廠模式詳解
一,概述
抽象工廠模式為一個產品家族提供了統一的建立介面。當需要這個產品家族的某一系列的時候,可以從抽象工廠中選出相對應的系列來建立一個具體的工廠類別。這種型別的設計模式屬於建立型模式,它提供了一種建立物件的最佳方式。
在抽象工廠模式中,介面是負責建立一個相關物件的工廠,不需要顯式指定它們的類。每個生成的工廠都能按照工廠模式提供物件。
相關術語:
-
產品等級結構:產品的繼承結構,與類的繼承相似。例如筆記本是一個抽象的類,那麼華為筆記本、蘋果和聯想筆記本就是其子類。
-
產品族:指同一個工廠生產的,位於不同的產品等級結構的一組產品。例如華為筆記本、手機、路由器等都產自華為,筆記本的等級結構不同,構成一個產品族。
-
抽象工廠:是一個介面,抽象工廠模式的核心,包含對多個產品等級結構的宣告,任何工廠類都必須實現這個介面。
- 具體工廠:是抽象工廠的實現,負責例項化某個產品族中的產品物件。例如華為工廠生產華為筆記本、手機、路由器等。
二,產品族和產品等級結構圖
我們以一個品牌為一個產品族,電腦、手機、路由器為產品等級,每一個品牌都有自己的產品族,這就構成一個完整產品群;
橫向代表一族,縱向代表一個等級,橫縱交集代表某一個品牌的某一個產品(比如下圖中交集的點為電腦),請看下圖;
三,UML圖
這個類圖其實比較簡單,簡單說明下:
產品頂級介面:主要被產品抽象類實現;
產品抽象類:某個具體產品要實現的類;
具體實現類:具體產品實現,比如華為路由器實現自抽象類AbstractRouter;
工廠介面:工廠介面中定義建立每個產品方法;
具體華為工廠:實現工廠介面,建立華為一族產品(路由器、手機、電腦);
四,具體程式碼實現
程式碼中我們以華為產品為例,分別定義華為電腦、手機、路由器產品,從UML類圖中可以看出我們的產品結構層級比較清晰,現在我們先設計我們產品。
下面開始定義產品;
產品頂級介面;
package pattern.abstractfactory.product; /** * 定義產品介面 * @author ningbeibei */ public interface InterfaceProduct { void get(); }
定義計算機抽象類並實現產品InterfaceProduct 介面;
package pattern.abstractfactory.product; /** * 定義計算機產品抽象類,並實現產品介面InterfaceProduct * @author ningbeibei */ public abstract class AbstractComputers implements InterfaceProduct { public abstract void get(); }
定義手機抽象類並實現產品InterfaceProduct 介面;
package pattern.abstractfactory.product; /** * 定義手機抽象類,並實現產品介面InterfaceProduct * @author ningbeibei */ public abstract class AbstractPhone implements InterfaceProduct { public abstract void get(); }
定義路由器抽象類並實現產品InterfaceProduct 介面;
package pattern.abstractfactory.product; /** * 定義路由器產品抽象類,並實現InterfaceProduct介面 * @author ningbeibei */ public abstract class AbstractRouter implements InterfaceProduct{ public abstract void get(); }
定義華為電腦具體實現類,繼承AbstractComputers抽象類;
package pattern.abstractfactory.product; /** * 華為電腦實現類 * @author ningbeibei */ public class HuaWeiComputer extends AbstractComputers{ @Override public void get() { System.out.println("華為筆記本"); } }
定義華為手機具體實現類,繼承AbstractPhone抽象類;
package pattern.abstractfactory.product; /** * 華為手機實現類, * @author ningbeibei */ public class HuaWeiPhone extends AbstractPhone{ @Override public void get() { System.out.println("華為手機"); } }
定義華為路由器具體實現類,繼承AbstractRouter抽象類;
package pattern.abstractfactory.product; /** * 華為路由器 * @author ningbeibei */ public class HuaWeiRouter extends AbstractRouter { @Override public void get() { System.out.println("華為品牌路由器"); } }
下面開始定義工廠;
定義工廠介面;
package pattern.abstractfactory.factory; import pattern.abstractfactory.product.InterfaceProduct; /** * 定義產品工廠介面, * @author ningbeibei */ public interface InterfactFactory { //手機產品 InterfaceProduct createPhone(); //電腦產品 InterfaceProduct createComputer(); //路由器產品 InterfaceProduct createRouter(); }
具體工廠實現類,實現 InterfactFactory 介面;
package pattern.abstractfactory.factory; import pattern.abstractfactory.product.HuaWeiComputer; import pattern.abstractfactory.product.HuaWeiPhone; import pattern.abstractfactory.product.HuaWeiRouter; import pattern.abstractfactory.product.InterfaceProduct; /** * 華為工廠 * @author ningbeibei */ public class HuaWeiFactory implements InterfactFactory { /** * 建立電腦物件並返回 */ @Override public InterfaceProduct createComputer() { return new HuaWeiComputer(); } /** * 建立手機物件並返回 */ @Override public InterfaceProduct createPhone() { return new HuaWeiPhone(); } /** * 建立路由器物件並返回 */ @Override public InterfaceProduct createRouter() { return new HuaWeiRouter(); } }
測試類;
package pattern.abstractfactory; import pattern.abstractfactory.factory.HuaWeiFactory; import pattern.abstractfactory.factory.InterfactFactory; import pattern.abstractfactory.product.InterfaceProduct; /** * 抽象工廠模式測試類 * @author ningbeibei */ public class test { public static void main(String[] args) { //建立華為品牌工廠 InterfactFactory huawei = new HuaWeiFactory(); //通過華為工廠獲取華為電腦物件 InterfaceProduct computer = huawei.createComputer(); computer.get(); //通過華為工廠獲取華為手機物件 InterfaceProduct phone = huawei.createPhone(); phone.get(); //通過華為工廠獲取華為路由器物件 InterfaceProduct router = huawei.createRouter(); router.get(); } }
執行結果;
五,抽象工廠方法模式如何擴充套件產品族
抽象工廠模式對於橫向擴充套件方便,對於縱向擴充套件非常困難,也就是說:假如我們要擴充套件一個新的品牌,比如擴充套件一個小米品牌,小米產品有電腦、手機、路由器,擴充套件新品牌就是橫向擴充套件,非常方便,但是我們要給小米新增一個電飯煲產品卻非常困難,這就是縱向擴充套件,所以在使用抽象工廠模式時一定要選擇合適的場景,也就是在不同場景中使用最適合的模式才是設計模式的精髓。
下面我們就來橫向擴充套件一個新品牌的產品族,需要新增電腦、手機、路由器具體類(小米品牌)程式碼如下;
小米電腦
package pattern.abstractfactory.product; /** * 小米電腦,繼承自 AbstractComputers 抽象類 * @author ningbeibei */ public class MiComputer extends AbstractComputers { @Override public void get() { System.out.println("小米電腦"); } }
小米手機
package pattern.abstractfactory.product; /** * 小米手機,繼承自 AbstractPhone 抽象類 * @author ningbeibei */ public class MiPhone extends AbstractPhone { @Override public void get() { System.out.println("小米手機"); } }
小米路由器
package pattern.abstractfactory.product; /** * 小米路由器,繼承自 AbstractRouter 抽象類 * @author ningbeibei */ public class MiRouter extends AbstractRouter{ @Override public void get() { System.out.println("小米路由器"); } }
新增小米具體工廠類
package pattern.abstractfactory.factory; import pattern.abstractfactory.product.InterfaceProduct; import pattern.abstractfactory.product.MiComputer; import pattern.abstractfactory.product.MiPhone; import pattern.abstractfactory.product.MiRouter; /** * 小米工廠,實現 InterfactFactory 介面 * @author ningbeibei */ public class MiFactory implements InterfactFactory{ //小米手機 @Override public InterfaceProduct createPhone() { return new MiPhone(); } //小米電腦 @Override public InterfaceProduct createComputer() { return new MiComputer(); } //小米路由器 @Override public InterfaceProduct createRouter() { return new MiRouter(); } }
最後編寫測試類,程式碼中紅色字型為新擴充套件的品牌產品;
package pattern.abstractfactory; import pattern.abstractfactory.factory.HuaWeiFactory; import pattern.abstractfactory.factory.InterfactFactory; import pattern.abstractfactory.factory.MiFactory; import pattern.abstractfactory.product.InterfaceProduct; /** * 抽象工廠模式測試類 * @author ningbeibei */ public class test { public static void main(String[] args) { // 建立華為品牌工廠 InterfactFactory huawei = new HuaWeiFactory(); // 通過華為工廠獲取華為電腦物件 InterfaceProduct computer = huawei.createComputer(); computer.get(); // 通過華為工廠獲取華為手機物件 InterfaceProduct phone = huawei.createPhone(); phone.get(); // 通過華為工廠獲取華為路由器物件 InterfaceProduct router = huawei.createRouter(); router.get(); // 建立小米品牌工廠 InterfactFactory Mifactory = new MiFactory(); // 通過小米工廠獲取小米電腦物件 InterfaceProduct micomputer = Mifactory.createComputer(); micomputer.get(); // 通過小米工廠獲取小米手機物件 InterfaceProduct miphone = Mifactory.createPhone(); miphone.get(); // 通過小米工廠獲取小米路由器物件 InterfaceProduct mirouter = Mifactory.createRouter(); mirouter.get(); } }
執行結果:
注意:通過上面的品牌擴充套件我們發現,橫向擴充套件容易,縱向擴充套件非常困難,程式碼可以非常方便的擴充套件一個品牌已有的產品,但要擴充套件一個未定義的產品卻異常困難,比如要擴充套件一個華為平板,需要修改工廠邏輯程式碼,新增產品結構,這顯然不符合設計模式開閉原則,所以在使用時一定要考慮清楚,確定不在有新的產品等級擴充套件。
六,優點和缺點及使用場景
優點
-
抽象工廠模式隔離了具體類的生成, 使得客戶並不需要知道什麼被建立。 由於這種隔離,更換一個具體工廠就變得相對容易, 所有的具體工廠都實現了抽象工廠中定義的那些公共介面, 因此只需改變具體工廠的例項, 就可以在某種程度上改變整個軟體系統的行為。
-
當一個族中的多個物件被設計成一起工作時, 它能夠保證客戶端始終只使用同一個族中的物件。
-
增加新的族很方便, 無須修改已有系統, 符合“開閉原則”。
缺點
- 增加新的等級結構麻煩, 需要對原有系統進行較大的修改, 甚至需要修改抽象層程式碼,這顯然會帶來較大的不便, 違背了“開閉原則”。
使用場景
-
一個系統不應當依賴於具體類例項如何被建立、 組合和表達的細節, 這對於所有型別的工廠模式都是很重要的, 使用者無須關心物件的建立過程, 將物件的建立和使用解耦。
-
系統中有多於一個的族, 而每次只使用其中某一族。 可以通過配置檔案等方式來使得使用者可以動態改變族, 也可以很方便地增加新的族。
-
等級結構穩定, 設計完成之後, 不會向系統中增加新的等級結構或者刪除已有的等級結構。
七,寫的不足之處還望批評指正
寫的不足之處請在評論區指出,便於我及時更正錯誤,避免給讀者帶來誤解,希望大家多多提意見。