摘要:一簡單工廠定義簡單工廠其實(shí)并不屬于種設(shè)計(jì)模式之一,該模式是工廠方法模式的弱化或者說是工廠方法模式的一種特例,因?yàn)楹唵危苑Q為簡單工廠模式,也叫做靜態(tài)工廠模式。
一、簡單工廠 定義
簡單工廠其實(shí)并不屬于23種GOF設(shè)計(jì)模式之一,該模式是工廠方法模式的弱化(或者說是工廠方法模式的一種特例),因?yàn)楹唵危苑Q為簡單工廠模式(Simple Factory Pattern),也叫做靜態(tài)工廠模式。雖然不是"標(biāo)準(zhǔn)"的設(shè)計(jì)模式(更像是一種編程習(xí)慣),但在實(shí)際項(xiàng)目中,采用該方法的案例還是比較多的。
簡單工廠模式?jīng)]有嚴(yán)格的定義,我們姑且使用以下描述:
提供一個(gè)創(chuàng)建對象實(shí)例的功能,而無須關(guān)心其具體實(shí)現(xiàn)。被創(chuàng)建實(shí)例的類型可以是接口、抽象類,也可以是具體的類關(guān)鍵點(diǎn)
具體的工廠類
創(chuàng)建產(chǎn)品的工廠方法
靜態(tài)方法(靜態(tài)工廠名字的由來)
通常會(huì)有一個(gè)"類型"參數(shù)(還有一種是可以提供多個(gè)靜態(tài)工廠方法并通過不同方法名區(qū)別要?jiǎng)?chuàng)建的產(chǎn)品)
根據(jù)參數(shù),利用if或者switch創(chuàng)建產(chǎn)品并返回
實(shí)現(xiàn) 抽象產(chǎn)品類(接口或抽象類)public interface Product { void doSomething(); void doAnything(); }具體產(chǎn)品類
public class ConcreteProductA implements Product { @Override public void doSomething() { System.out.println("ConcreteProductA doSomething"); } @Override public void doAnything() { System.out.println("ConcreteProductA doAnything"); } }
public class ConcreteProductB implements Product { @Override public void doSomething() { System.out.println("ConcreteProductB doSomething"); } @Override public void doAnything() { System.out.println("ConcreteProductB doAnything"); } }工廠類
public class Creator { public static Product createProduct(String type) { Product product = null; switch (type) { case "A": product = new ConcreteProductA(); break; case "B": product = new ConcreteProductB(); break; } return product; } }客戶端代碼
public class Client { public static void main(String[] args) { Product productA = Creator.createProduct("A"); productA.doSomething(); productA.doAnything(); Product productB = Creator.createProduct("B"); productB.doSomething(); productB.doAnything(); } }優(yōu)點(diǎn)
簡單
解耦
客戶端不需要依賴具體的產(chǎn)品類,只依賴工廠類,傳入不同的參數(shù)就可以得到不同的對象;
工廠方法可以根據(jù)用戶條件返回同一類型的不同子類;
工廠方法中可以增加額外創(chuàng)建對象的細(xì)節(jié),并且對客戶端屏蔽這些細(xì)節(jié)。
缺點(diǎn)工廠類的擴(kuò)展比較困難,每增加一個(gè)產(chǎn)品,就要在工廠中添加相應(yīng)的分支,對擴(kuò)展開放的同時(shí)對修改也開放了,不符合開閉原則。如果有很多產(chǎn)品,那么工廠方法會(huì)顯得特別"臃腫",降低可讀性且不易維護(hù)。
使用場景new的替代品,需要用new創(chuàng)建對象的地方都可以考慮簡單工廠;
產(chǎn)品種類較少,并且基本可以預(yù)見不需要太多擴(kuò)展的情況(產(chǎn)品需求基本已經(jīng)確定,例如計(jì)算器,已知的運(yùn)算類型大概就那么多種)
二、工廠方法 定義Define an interface for creating an object,but let subclasses decide which class toinstantiate.Factory Method lets a class defer instantiation to subclasses.實(shí)現(xiàn) 抽象產(chǎn)品類定義一個(gè)用于創(chuàng)建對象的接口,讓子類決定實(shí)例化哪一個(gè)類。工廠方法使一個(gè)類的實(shí)例化延遲到其子類。
public interface Product { void doSomething(); void doAnything(); }具體產(chǎn)品類
public class ConcreteProductA implements Product { @Override public void doSomething() { System.out.println("ConcreteProductA doSomething"); } @Override public void doAnything() { System.out.println("ConcreteProductA doAnything"); } }
public class ConcreteProductB implements Product { @Override public void doSomething() { System.out.println("ConcreteProductB doSomething"); } @Override public void doAnything() { System.out.println("ConcreteProductB doAnything"); } }抽象工廠類
public interface Creator { Product createProduct(); }具體工廠類
public class ConcreteCreatorA implements Creator { @Override public Product createProduct() { return new ConcreteProductA(); } }
public class ConcreteCreatorB implements Creator { @Override public Product createProduct() { return new ConcreteProductB(); } }客戶端代碼
public static void main(String[] args) { Creator creatorA = new ConcreteCreatorA(); Product productA = creatorA.createProduct(); productA.doSomething(); productA.doAnything(); Creator creatorB = new ConcreteCreatorB(); Product productB = creatorB.createProduct(); productB.doSomething(); productB.doAnything(); }優(yōu)點(diǎn)
良好的封裝性,代碼結(jié)構(gòu)清晰
一個(gè)對象創(chuàng)建是有條件約束的,如一個(gè)調(diào)用者需要一個(gè)具體的產(chǎn)品對象,只要知道這個(gè)產(chǎn)品的類名(或約束字符串)就可以了,不用知道創(chuàng)建對象的艱辛過程,降低模塊間的耦合。
工廠方法模式的擴(kuò)展性非常優(yōu)秀
在增加產(chǎn)品類的情況下,只要適當(dāng)?shù)匦薷木唧w的工廠類或擴(kuò)展一個(gè)工廠類,就可以完成“擁抱變化”。
工廠方法模式是典型的解耦框架
高層模塊值需要知道產(chǎn)品的抽象類,其他的實(shí)現(xiàn)類都不用關(guān)心,符合迪米特法則,我不需要的就不要去交流;也符合依賴倒置原則,只依賴產(chǎn)品類的抽象;當(dāng)然也符合里氏替換原則,使用產(chǎn)品子類替換產(chǎn)品父類。
缺點(diǎn)每增加一個(gè)產(chǎn)品類,就需要增加一個(gè)對應(yīng)的工廠類,增加了額外的開發(fā)量。
擴(kuò)展利用反射機(jī)制來解決"每增加一個(gè)產(chǎn)品類,就需要增加一個(gè)對應(yīng)的工廠類"的問題
抽象工廠類public interface Creator {具體工廠類T createProduct(Class clazz); }
public class ConcreteCreator implements Creator { @Override public客戶端代碼T createProduct(Class clazz) { Product product= null; try { product = (Product) Class.forName(clazz.getName()).newInstance(); } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) { e.printStackTrace(); } return (T) product; } }
public class Client { public static void main(String[] args) { Creator creator = new ConcreteCreator(); Product productA = creator.createProduct(ConcreteProductA.class); productA.doSomething(); productA.doAnything(); Product productB = creator.createProduct(ConcreteProductB.class); productB.doSomething(); productB.doAnything(); } }工廠方法 VS 簡單工廠
工廠方法模式是對簡單工廠的進(jìn)一步抽象和解耦。和簡單工廠比:
工廠方法模式多了一個(gè)抽象工廠類
每個(gè)產(chǎn)品都對應(yīng)一個(gè)具體的工廠類
工廠方法模式把簡單工廠的內(nèi)部邏輯判斷轉(zhuǎn)移到了客戶端代碼來進(jìn)行。各個(gè)實(shí)例對象的創(chuàng)建代碼,沒有耦合在同一個(gè)工廠類里。
工廠方法模式更易于擴(kuò)展,克服了簡單工廠會(huì)違背開閉原則的缺點(diǎn),又保持了封裝對象創(chuàng)建過程的優(yōu)點(diǎn)。
三、抽象工廠 定義Provide an interface for creating families of related or dependent objects without specifyingtheir concrete classes.實(shí)現(xiàn) 抽象產(chǎn)品類為創(chuàng)建一組相關(guān)或相互依賴的對象提供一個(gè)接口,而且無須指定它們的具體類。
產(chǎn)品A家族
public interface ProductA { void doSomething(); void doAnything(); }
產(chǎn)品B家族
public interface ProductB { void doSomething(); void doAnything(); }具體產(chǎn)品類
產(chǎn)品A家族,產(chǎn)品等級1
public class ConcreteProductA1 implements ProductA { @Override public void doSomething() { System.out.println("ConcreteProductA1 doSomething"); } @Override public void doAnything() { System.out.println("ConcreteProductA1 doAnything"); } }
產(chǎn)品A家族,產(chǎn)品等級2
public class ConcreteProductA2 implements ProductA { @Override public void doSomething() { System.out.println("ConcreteProductA2 doSomething"); } @Override public void doAnything() { System.out.println("ConcreteProductA2 doAnything"); } }
產(chǎn)品B家族,產(chǎn)品等級2
public class ConcreteProductB1 implements ProductB { @Override public void doSomething() { System.out.println("ConcreteProductB1 doSomething"); } @Override public void doAnything() { System.out.println("ConcreteProductB1 doAnything"); } }
產(chǎn)品B家族,產(chǎn)品等級2
public class ConcreteProductB2 implements ProductB { @Override public void doSomething() { System.out.println("ConcreteProductB2 doSomething"); } @Override public void doAnything() { System.out.println("ConcreteProductB2 doAnything"); } }抽象工廠類
public interface Creator { /** * 創(chuàng)建A產(chǎn)品家族 * @return */ ProductA createProductA(); /** * 創(chuàng)建B產(chǎn)品家族 * @return */ ProductB createProductB(); // ... // 有N個(gè)產(chǎn)品族,在抽象工廠類中就應(yīng)該有N個(gè)創(chuàng)建方法 }
有N個(gè)產(chǎn)品族,在抽象工廠類中就應(yīng)該有N個(gè)創(chuàng)建方法
具體工廠類public class ConcreteCreator1 implements Creator { @Override public ProductA createProductA() { return new ConcreteProductA1(); } @Override public ProductB createProductB() { return new ConcreteProductB1(); } }
public class ConcreteCreator2 implements Creator { @Override public ProductA createProductA() { return new ConcreteProductA2(); } @Override public ProductB createProductB() { return new ConcreteProductB2(); } }
有M個(gè)產(chǎn)品等級,就應(yīng)該有M個(gè)具體工廠實(shí)現(xiàn)
客戶端代碼public class Client { public static void main(String[] args) { Creator creator1 = new ConcreteCreator1(); ProductA productA1 = creator1.createProductA(); productA1.doSomething(); productA1.doAnything(); ProductB productB1 = creator1.createProductB(); productB1.doSomething(); productB1.doAnything(); Creator creator2 = new ConcreteCreator2(); ProductA productA2 = creator2.createProductA(); productA2.doSomething(); productA2.doAnything(); ProductB productB2 = creator2.createProductB(); productB2.doSomething(); productB2.doAnything(); } }優(yōu)點(diǎn)
封裝性,高層模塊不需要關(guān)心每個(gè)產(chǎn)品的實(shí)現(xiàn)類,不關(guān)心對象是如何創(chuàng)建出來的,只要知道工廠類是誰,就能創(chuàng)建出一個(gè)需要的對象
一個(gè)產(chǎn)品族中的多個(gè)對象被設(shè)計(jì)成一起工作時(shí),它能保證客戶端始終只使用同一個(gè)產(chǎn)品族中的對象,并且很容易交換產(chǎn)品系列
可以定義產(chǎn)品族內(nèi)的約束,并且這樣的約束對高層模塊來說是透明的
缺點(diǎn)抽象工廠模式的最大缺點(diǎn)就是產(chǎn)品族擴(kuò)展非常困難,以上面的通用代碼為例,如果要增加一個(gè)產(chǎn)品C,也就是說產(chǎn)品家族由原來的2個(gè)增加到3個(gè),抽象工廠類Creator要增加一個(gè)方法createProductC(),然后每個(gè)實(shí)現(xiàn)類都要修改,違反了開閉原則。
注意是產(chǎn)品族擴(kuò)展困難,而不是產(chǎn)品等級,如果新增一個(gè)產(chǎn)品等級,只需增加一個(gè)具體工廠類的實(shí)現(xiàn)即可完成擴(kuò)展
抽象工廠 VS 工廠方法抽象工廠模式是工廠方法模式的升級版本,在有多個(gè)業(yè)務(wù)品種、業(yè)務(wù)分類時(shí),通過抽象工廠模式產(chǎn)生需要的對象是一種非常好的解決方式。
工廠方法模式生產(chǎn)一個(gè)產(chǎn)品,抽象工廠模式生產(chǎn)多個(gè)產(chǎn)品(一系列產(chǎn)品);在編程中,通常表現(xiàn)為一個(gè)接口或者抽象類,也就是說,工廠方法模式提供的所有產(chǎn)品都是衍生自同一個(gè)接口或抽象類,而抽象工廠模式所提供的產(chǎn)品則是衍生自不同的接口或抽象類。
四、總結(jié)簡單工廠、工廠方法、抽象工廠這三種模式是逐步抽象的,后者適用于更為一般的場景,而前者是后者的特例。但它們的目標(biāo)是殊途同歸的,目的都是靈活地創(chuàng)建所需的對象并且對客戶端隱藏對象創(chuàng)建細(xì)節(jié),三者的擴(kuò)展性和開發(fā)量有所不同,可以根據(jù)實(shí)際情況選擇合適的模式來代替以new的方式創(chuàng)建對象的過程:
簡單工廠適用于產(chǎn)品種類較少,且不需要太多擴(kuò)展的場景
工廠方法模式作為簡單工廠的進(jìn)一步抽象和補(bǔ)充,更加適用于有很多擴(kuò)展需求的場景
如果一個(gè)產(chǎn)品族都有相同的約束(在有多個(gè)業(yè)務(wù)品種、業(yè)務(wù)分類時(shí),即:具有產(chǎn)品族&產(chǎn)品等級結(jié)構(gòu)的概念),則可以使用抽象工廠模式
例如一個(gè)文本編輯器和一個(gè)圖片處理器,都是軟件實(shí)體,但是*nix下的文本編輯器和Windows下的文本編輯器雖然功能和界面都相同,但是代碼實(shí)現(xiàn)是不同的,圖片處理器也有類似情況。也就是具有了共同的約束條件:操作系統(tǒng)類型。于是我們可以使用抽象工廠模式,產(chǎn)生不同操作系統(tǒng)下的編輯器和圖片處理器。
源碼地址:https://gitee.com/tianranll/java-design-patterns.git
參考文獻(xiàn):《設(shè)計(jì)模式之禪》、《大話設(shè)計(jì)模式》
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/77756.html
摘要:用專業(yè)的話來講設(shè)計(jì)模式是一套被反復(fù)使用多數(shù)人知曉的經(jīng)過分類編目的代碼設(shè)計(jì)經(jīng)驗(yàn)的總結(jié)創(chuàng)建型模式,共五種工廠方法模式抽象工廠模式單例模式建造者模式原型模式。工廠方法模式的擴(kuò)展性非常優(yōu)秀。工廠方法模式是典型的解耦框架。 前言 最近一直在Java方向奮斗《終于,我還是下決心學(xué)Java后臺了》,今天抽空開始學(xué)習(xí)Java的設(shè)計(jì)模式了。計(jì)劃有時(shí)間就去學(xué)習(xí),你這么有時(shí)間,還不來一起上車嗎? 之所以要學(xué)...
摘要:我認(rèn)為按書上的順序比較好理解因?yàn)楹唵戊o態(tài)工廠模式是在工廠方法模式上縮減,抽象工廠模式是在工廠方法模式上再增強(qiáng)。所以我就先講工廠方法模式了。抽象工廠模式抽象工廠模式就比較復(fù)雜了,我們一般的應(yīng)用都寫不到。 前言 只有光頭才能變強(qiáng) 回顧前面: 給女朋友講解什么是代理模式 包裝模式就是這么簡單啦 單例模式你會(huì)幾種寫法? 昨天寫了單例模式了,今天是時(shí)候?qū)懝S模式啦~ 工廠模式我個(gè)人認(rèn)為其實(shí)比...
摘要:所謂的產(chǎn)品族,一般或多或少的都存在一定的關(guān)聯(lián),抽象工廠模式就可以在類內(nèi)部對產(chǎn)品族的關(guān)聯(lián)關(guān)系進(jìn)行定義和描述,而不必專門引入一個(gè)新的類來進(jìn)行管理。 0x01.定義與類型 定義:抽象工廠模式提供一個(gè)創(chuàng)建一系列相關(guān)或相互依賴對象的接口 無需指定它們具體的類 類型:創(chuàng)建型 UML showImg(https://segmentfault.com/img/bVbtBp1?w=800&h=862...
摘要:工廠方法模式和策略的模式有什么區(qū)別區(qū)別在于,策略模式強(qiáng)調(diào)的是提供不同的策略方案,而工廠方法模式強(qiáng)調(diào)的是產(chǎn)品本身。 女朋友dodo鬧脾氣,氣勢洶洶的說我要吃雪糕。筆者心里啊樂滋滋的,一支雪糕就能哄回來,不亦樂乎?! 但是,雪糕買回來了,她竟然說不想吃雪糕了,突然想吃披薩。呵呵了,憋了一股勁沒問題,又屁顛屁顛的去把披薩買回來。 世事難料,dodo同學(xué)又放大招了,披薩太上火了,我要吃芝士蛋糕...
閱讀 1740·2021-11-25 09:43
閱讀 1785·2021-11-24 10:41
閱讀 3105·2021-09-27 13:36
閱讀 811·2019-08-30 15:53
閱讀 3567·2019-08-30 15:44
閱讀 866·2019-08-30 14:03
閱讀 2572·2019-08-29 16:38
閱讀 996·2019-08-29 13:23