工廠模式主要是爲建立對象提供接口,將建立對象的過程隔離起來,實現了建立者與調用者的分離,提升了程序的靈活性;html
核心本質:
實例化對象,用工廠方法代替new操做;
將選擇實現類、建立對象統一管理和控制,從而將調用者跟咱們實現類解耦;java
工廠模式分類:
簡單工廠模式(Simple Factory)(又稱:靜態工廠方法模式)
工廠方法模式(Factory Method)
抽象工廠模式(Abstract Factory)git
GOF在《設計模式》一書中將工廠模式分爲兩類:工廠方法模式(Factory Method)與抽象工廠模式(Abstract Factory),將簡單工廠模式(Simple Factory)看爲工廠方法模式的一種特例,二者歸爲一類;github
類型:建立型模式編程
簡單工廠模式又被稱爲靜態工廠方法模式;設計模式
簡單工廠模式是由一個工廠(注意是一個!)對象決定建立出哪種產品類的實例;ide
實現方式的實質:由一個工廠類根據傳入的參數,動態決定應該建立哪個產品類(這些產品類繼承自一個父類或接口)的實例;測試
現實生活中,工廠是負責生產產品的;一樣在設計模式中,簡單工廠模式咱們能夠理解爲負責生產對象的一個類,稱爲「工廠類」;優化
英文:Simple Factoryui
將「類實例化的操做」與「使用對象的操做」分開,讓使用者不用知道具體參數就能夠實例化出所須要的「產品」類,從而避免了在客戶端代碼中顯式指定,實現瞭解耦;
即便用者可直接消費產品而不須要知道其生產的細節;
背景:這有一個手機生產工廠,能生產多種手機
先定義一個抽象手機類:
package com.designmode.factory.simple; /** * 類說明 :抽象手機類 */ public abstract class Mobile { }
定義具體的手機:小米手機
package com.designmode.factory.simple; /** * 類說明 :具體手機--小米手機 */ public class XiaomiMobile extends Mobile{ }
定義具體的手機:華爲手機
package com.designmode.factory.simple; /** * 類說明 :具體手機--華爲手機 */ public class HuaweiMobile extends Mobile{ }
最後定義一個工廠:
package com.designmode.factory.simple; /** * 類說明 : */ public class MobileFactory { /** * 靜態工廠方法 * @param mobiletype * @return */ public static Mobile product(String mobiletype){ Mobile mobile = null; if ("xiaomi".equals(mobiletype)) { mobile = new XiaomiMobile(); System.out.println("生產小米手機."); } else if ("huawei".equals(mobiletype)) { mobile = new HuaweiMobile(); System.out.println("生產華爲手機."); } else { System.out.println("不能生產該手機類型."); } return mobile; } }
下面我們來生產手機:
package com.designmode.factory.simple; /** * 類說明 :測試 */ public class Test { public static void main(String[] args) { /** * 客戶要訂購生產小米手機 */ MobileFactory.product("xiaomi"); /** * 客戶要訂購生產華爲手機 */ MobileFactory.product("huawei"); /** * 客戶要訂購生產錘子手機 */ MobileFactory.product("chuizi"); } }
結果:
生產小米手機. 生產華爲手機. 不能生產該手機類型.
優勢:
將建立實例的工做與使用實例的工做分開,使用者沒必要關心類對象如何建立,只須要傳入工廠須要的參數便可;
把初始化實例時的工做放到工廠裏進行,使代碼更容易維護;
更符合面向對象的原則 & 面向接口編程;
缺點:
工廠類集中了全部實例(產品)的建立邏輯,一旦這個工廠不能正常工做,整個系統都會受到影響;
違背「開放 - 關閉原則」,一旦添加新產品就不得不修改工廠類的邏輯,這樣就會形成工廠邏輯過於複雜,對於系統維護和擴展不夠友好;
簡單工廠模式因爲使用了靜態工廠方法,靜態方法不能被繼承和重寫,會形成工廠角色沒法造成基於繼承的等級結構;
(1) 工廠類負責建立的對象比較少,因爲建立的對象較少,不會形成工廠方法中的業務邏輯太過複雜
(2) 客戶端只知道傳入工廠類的參數,對於如何建立對象並不關心
(3) 鑑於該模式的缺點,所以通常只在很簡單的狀況下應用該模式
工廠方法模式,又稱工廠模式、多態工廠模式和虛擬構造器模式,經過定義工廠父類負責定義建立對象的公共接口,而子類則負責生成具體的對象;
抽象工廠是工廠方法模式的核心,全部建立對象的工廠類都必須實現該接口;
英文:Factory Method
定義:定義一個用於建立對象的接口,讓子類決定實例化哪個類,Factory Method使一個類的實例化延遲到了子類;
工廠一旦須要生產新產品就須要修改工廠類的方法邏輯,違背了「開放 - 關閉原則「
即簡單工廠模式的缺點
之因此能夠解決簡單工廠的問題,是由於工廠方法模式把具體產品的建立推遲到工廠類的子類(具體工廠)中,此時工廠類再也不負責全部產品的建立,而只是給出具體工廠必須實現的接口,這樣工廠方法模式在添加新產品的時候就不修改工廠類邏輯而是添加新的工廠子類,符合開放封閉原則,克服了簡單工廠模式中缺點
定義一個抽象手機類
package com.designmode.factory.method; /** * 類說明 :抽象手機類 */ public abstract class Mobile { }
定義一個具體手機類 - 小米手機
package com.designmode.factory.method; /** * 類說明 :具體手機--小米手機 */ public class XiaomiMobile extends Mobile{ }
定義一個具體手機類 - 華爲手機
package com.designmode.factory.method; /** * 類說明 :具體手機--華爲手機 */ public class HuaweiMobile extends Mobile{ }
定義一個抽象工廠接口
package com.designmode.factory.method; /** * 類說明 :抽象手機生產工廠 */ public abstract interface MobileFactory { public abstract Mobile product(); }
定義具體工廠 - 小米手機生產工廠
package com.designmode.factory.method; /** * 類說明 :具體工廠類 - 小米工廠 */ public class XiaomiFactory implements MobileFactory{ @Override public Mobile product() { System.out.println("生產小米手機."); return new XiaomiMobile(); } }
定義具體工廠 - 華爲手機生產工廠
package com.designmode.factory.method; /** * 類說明 :具體工廠類 - 華爲工廠 */ public class HuaweiFactory implements MobileFactory{ @Override public Mobile product() { System.out.println("生產華爲手機."); return new HuaweiMobile(); } }
下面測試生產小米手機,華爲手機
package com.designmode.factory.method; /** * 類說明 :測試 */ public class Test { public static void main(String[] args) { MobileFactory factory = null; factory = new XiaomiFactory(); factory.product(); factory = new HuaweiFactory(); factory.product(); } }
結果:
生產小米手機. 生產華爲手機.
優勢:
更符合開-閉原則,新增一種產品時,只須要增長相應的具體產品類和相應的工廠子類便可;
符合單一職責原則,每一個具體工廠類只負責建立對應的產品;
總結:工廠模式能夠說是簡單工廠模式的進一步抽象和拓展,在保留了簡單工廠的封裝優勢的同時,讓擴展變得簡單,讓繼承變得可行,增長了多態性的體現;
缺點:
添加新產品時,除了增長新產品類外,還要提供與之對應的具體工廠類,系統類的個數將成對增長,在必定程度上增長了系統的複雜度;同時,有更多的類須要編譯和運行,會給系統帶來一些額外的開銷;
因爲考慮到系統的可擴展性,須要引入抽象層,在客戶端代碼中均使用抽象層進行定義,增長了系統的抽象性和理解難度,且在實現時可能須要用到DOM、反射等技術,增長了系統的實現難度;
雖然保證了工廠方法內的對修改關閉,但對於使用工廠方法的類,若是要更換另一種產品,仍然須要修改實例化的具體工廠類;
一個具體工廠只能建立一種具體產品;
(1) 客戶端不知道它所須要的對象的類。在工廠方法模式中,客戶端不須要知道具體產品類的類名,只須要知道所對應的工廠便可,具體的產品對象由具體工廠類建立;
(2) 抽象工廠類經過其子類來指定建立哪一個對象。在工廠方法模式中,對於抽象工廠類只須要提供一個建立產品的接口,而由其子類來肯定具體要建立的對象;
抽象工廠模式爲建立一組對象提供了一種解決方案。與工廠方法模式相比,抽象工廠模式中的具體工廠不僅是建立一種產品,它負責建立一族產品;
英文:Abstract Factory
定義:提供一個建立一系列相關或相互依賴對象的接口,而無須指定它們的具體類;
每一個工廠只能建立一類產品
即工廠方法模式的缺點
建立一個產品抽象族
package com.designmode.factory.absract; /** * 類說明 :抽象產品族 */ public abstract class AbstractProduct { }
建立一個手機抽象類
package com.designmode.factory.absract; /** * 類說明 :抽象手機類 */ public abstract class Mobile extends AbstractProduct{ }
建立一個MP3抽象類
package com.designmode.factory.absract; /** * 類說明 :抽象MP3類 */ public abstract class MP3 extends AbstractProduct{ }
建立一個具體手機類 - 小米手機
package com.designmode.factory.absract; /** * 類說明 :具體手機--小米手機 */ public class XiaomiMobile extends Mobile{ }
建立一個具體手機類 - 華爲手機
package com.designmode.factory.absract; /** * 類說明 :具體手機--華爲手機 */ public class HuaweiMobile extends Mobile{ }
建立一個具體MP3類 - 小米MP3
package com.designmode.factory.absract; /** * 類說明 :具體MP3--小米MP3 */ public class XiaomiMP3 extends MP3{ }
建立一個具體MP3類 - 華爲MP3
package com.designmode.factory.absract; /** * 類說明 :具體MP3--華爲MP3 */ public class HuaweiMP3 extends MP3{ }
建立抽象工廠類
package com.designmode.factory.absract; /** * 類說明 :抽象工廠類 */ public abstract interface AbstractFactory { public abstract Mobile productMobile(); public abstract MP3 productMP3(); }
建立具體工廠類 - 小米工廠
package com.designmode.factory.absract; /** * 類說明 :小米工廠類 */ public class XiaomiFactory implements AbstractFactory{ @Override public Mobile productMobile() { System.out.println("生產小米手機."); return new XiaomiMobile(); } @Override public MP3 productMP3() { System.out.println("生產小米MP3."); return new XiaomiMP3(); } }
建立具體工廠類 - 華爲工廠
package com.designmode.factory.absract; /** * 類說明 :華爲工廠類 */ public class HuaweiFactory implements AbstractFactory{ @Override public Mobile productMobile() { System.out.println("生產華爲手機."); return new HuaweiMobile(); } @Override public MP3 productMP3() { System.out.println("生產華爲MP3."); return new HuaweiMP3(); } }
下面測試一下:生產 小米手機、MP3;華爲手機、MP3
package com.designmode.factory.absract; /** * 類說明 :測試 */ public class Test { public static void main(String[] args) { AbstractFactory factory = null; factory = new XiaomiFactory(); factory.productMobile(); factory.productMP3(); factory = new HuaweiFactory(); factory.productMobile(); factory.productMP3(); } }
結果:
生產小米手機. 生產小米MP3. 生產華爲手機. 生產華爲MP3.
優勢:
1)分離接口和實現
客戶端使用抽象工廠來建立須要的對象,而客戶端根本就不知道具體的實現是誰,客戶端只是面向產品的接口編程而已。也就是說,客戶端從具體的產品實現中解耦;
2)使切換產品族變得容易
由於一個具體的工廠實現表明的是一個產品族,拿上面的代碼來講,就是從「小米」到「華爲」只須要切換一下具體的工廠便可;
缺點:
1)不太容易擴展新的產品
若是須要給整個產品族添加一個新的產品,那麼就須要修改抽象工廠,這樣就會致使修改全部的工廠實現類;
爲建立一組對象提供了一種解決方案;
簡單工廠模式:
簡單工廠類負責了全部產品的建立邏輯,當咱們須要新引進一個新產品時,就不得不修改工廠類的產品建立邏輯,在產品類型較多時有可能會形成工廠類的產品建立邏輯過於負責,不利於系統的維護性和擴展性;
工廠方法模式:
對簡單工廠模式的設計優化,簡單工廠模式中若是新增一類產品類型時,須要修改工廠靜態方法的產品建立邏輯,而使用工廠方法模式只需新擴展出一個新的工廠子類或是實現類來針對新增類型產品的建立工做、使系統具備了良好的擴展性與維護性;
抽象工廠模式:
爲建立一組對象提供了一種解決方案,與工廠方法模式相比,抽象工廠模式中的具體工廠不僅是建立一種產品,它負責建立一族產品;
PS:源碼地址 https://github.com/JsonShare/DesignPattern/tree/master