java設(shè)計(jì)模式之抽像工廠詳解
一、概念
提供一個(gè)創(chuàng)建一系列相關(guān)或相互依賴對(duì)像的接口,而無需指定它們具體的類。
二、模式動(dòng)機(jī)
這一系列對(duì)像之間是相互依賴的,相當(dāng)于一個(gè)產(chǎn)品族
三、模式的結(jié)構(gòu)
通過上圖我們可以清楚的看到抽像工廠模式包括以下4個(gè)角色:
1.抽像工廠角色(AbstractFactory):抽像工廠模式的核心,與具體的商業(yè)邏輯無關(guān),通常是一個(gè)JAVA接口或者抽像類。
2.具體工廠角色(Concrete Factory):該角色通常與具體的商業(yè)邏輯緊密相關(guān),該角色里面的工廠方法依據(jù)具體的商業(yè)邏輯實(shí)例化具體的產(chǎn)品并返回,客戶端通過該角色并調(diào)用該角色的工廠方法,獲得具體產(chǎn)品對(duì)像,該角色通常都是一個(gè)具體JAVA類來承擔(dān)。
3.抽像產(chǎn)品角色:擔(dān)任這個(gè)角色的類是工廠方法模式所創(chuàng)建的產(chǎn)品的父類,或者他們共同擁有的接口,通常是一個(gè)接口或者抽像類。
4.具體產(chǎn)品角色:抽像工廠模式所創(chuàng)建的任何產(chǎn)品都是這個(gè)角色的實(shí)例,有一個(gè)具體JAVA類來承擔(dān)。
樣例代碼如下:
public class AbstractProductA { /** * @roseuid 59AC05990327 */ public AbstractProductA() { } } public class ProductA1 extends AbstractProductA { /** * @roseuid 59AC05990359 */ public ProductA1() { } } public class ProductA2 extends AbstractProductA { /** * @roseuid 59AC05990381 */ public ProductA2() { } } public class AbstractProductB { /** * @roseuid 59AC059903BA */ public AbstractProductB() { } } public class ProductB1 extends AbstractProductB { /** * @roseuid 59AC059A001F */ public ProductB1() { } } public class ProductB2 extends AbstractProductB { /** * @roseuid 59AC059A0049 */ public ProductB2() { } } public abstract class AbstractFactory { /** * @roseuid 59AC05690005 */ public AbstractFactory() { } /** * @return AbstractProductA * @roseuid 59ABFB0103BE */ public Abstract AbstractProductA createProductA() ; /** * @return AbstractProductB * @roseuid 59ABFB3B029D */ public Abstract AbstractProductB createProductB() ; } public class ConcreteFactory1 extends AbstractFactory { /** * @roseuid 59AC057A02FC */ public ConcreteFactory1() { } /** * @return AbstractProductA * @roseuid 59ABFB9C00C9 */ public AbstractProductA createProductA() { return new ProductA1(); } /** * @return AbstractProductB * @roseuid 59ABFBA30011 */ public AbstractProductB createProductB() { return new ProductB1(); } } public class ConcreteFactory2 extends AbstractFactory { /** * @roseuid 59AC057A02C0 */ public ConcreteFactory2() { } /** * @return AbstractProductA * @roseuid 59ABFCC701B9 */ public AbstractProductA createProductA() { return new ProductA2(); } /** * @return AbstractProductB * @roseuid 59ABFCC9001F */ public AbstractProductB createProductB() { return new ProductB2(); } }
public class Client { /** * @roseuid 59AC055700AB */ public Client() { } public static void main(String[] args){ AbstractFactory theAbstractFactory; AbstractProductA theAbstractProductA; AbstractProductB theAbstractProductB; theAbstractFactory=new ConcreteFactory1(); theAbstractProductA=theAbstractFactory.createProductA(); theAbstractProductB=theAbstractFactory.createProductB(); } }
跟據(jù)上面的模式結(jié)構(gòu)圖我們對(duì)“提供一個(gè)創(chuàng)建一系列相關(guān)或相互依賴對(duì)像的接口,而無需指定它們具體的類” 進(jìn)行一個(gè)簡(jiǎn)要的分析:
1.相關(guān)或相互依賴對(duì)像,在這里面ProductA1的實(shí)例和ProductB1的實(shí)例就是一組相互關(guān)聯(lián)(如內(nèi)在的關(guān)聯(lián)關(guān)系)或相互依賴(如整體和部分)關(guān)系,依據(jù)業(yè)務(wù)邏輯,ProductA1
只能和同一產(chǎn)品等級(jí)結(jié)構(gòu)AbstractProductB下的ProductB1相互關(guān)聯(lián)而無法與ProductB2關(guān)聯(lián)在一起。
2.提供一個(gè)創(chuàng)建一系列相關(guān)或相互依賴對(duì)像的接口,而無需指定它們具體的類,這里面的接口,即為結(jié)構(gòu)圖中的AbstractProductA和AbstractProductB,客戶端只依賴這些產(chǎn)品的接口進(jìn)行編程,而不依賴于具體實(shí)現(xiàn),即符合依賴倒轉(zhuǎn)原則?!盁o需指定它們具體的類” 即客戶端(client)跟本就不知道ProductA1、ProductA2、ProductB1和ProductB2的存在,客戶端只需要調(diào)用具體工廠的工廠方法即可返回具體的產(chǎn)品實(shí)例。
四、模式樣例
我們接著工廠方法模式中的樣例進(jìn)行進(jìn)一步分析,現(xiàn)在這個(gè)生產(chǎn)輪胎的工廠已經(jīng)不滿足只生產(chǎn)轎車輪胎了,他現(xiàn)已經(jīng)引入了發(fā)動(dòng)機(jī)的生產(chǎn)線(EngineLine)、車門(DoorLine)等整個(gè)車的各種零部件生產(chǎn)線,可以說他現(xiàn)在可以輕松制造一部Car,但是也并非所有的Car都能制造,比如他現(xiàn)只能生產(chǎn)benz和BMW兩種類型的車(這樣的工廠也夠NX了),比如現(xiàn)在一部車只包含車輪胎、車門和發(fā)動(dòng)機(jī)(當(dāng)然肯定不止這么多),那么這個(gè)工廠就可以跟據(jù)客戶的要求生產(chǎn)BMW和benz車了,如下圖:
代碼如下:
public interface Door { public void open(); public void close(); } public class BenzDoor implements Door { @Override public void open() { System.out.println("奔馳車門開"); } @Override public void close() { System.out.println("奔馳車門關(guān)"); } } public class BmwDoor implements Door { @Override public void open() { System.out.println("寶馬車門開"); } @Override public void close() { System.out.println("寶馬車門關(guān)"); } } public interface Tire { public void getColor(); public void getLife(); public void getWidth(); } public class BenzTire implements Tire { @Override public void getColor() { System.out.println("benz車color"); } @Override public void getLife() { System.out.println("benz車life"); } @Override public void getWidth() { System.out.println("benz車width"); } } public class BmwTire implements Tire { @Override public void getColor() { System.out.println("bmw車color"); } @Override public void getLife() { System.out.println("bmw車life"); } @Override public void getWidth() { System.out.println("bmw車width"); } } public interface Engine { public void start(); public void stop(); } public class BenzEngine implements Engine { @Override public void start() { System.out.println("benz車start"); } @Override public void stop() { System.out.println("benz車stop"); } } public class BmwEngine implements Engine { @Override public void start() { System.out.println("bmw車start"); } @Override public void stop() { System.out.println("bmw車stop"); } } public interface PartFactory { public Door createDoor(); public Tire createTire(); public Engine createEngine(); } public class BenzPartFactory implements PartFactory { @Override public Door createDoor() { return new BenzDoor(); } @Override public Tire createTire() { return new BenzTire(); } @Override public Engine createEngine() { return new BenzEngine(); } } public class BmwPartFactory implements PartFactory { @Override public Door createDoor() { return new BmwDoor(); } @Override public Tire createTire() { return new BmwTire(); } @Override public Engine createEngine() { return new BmwEngine(); } } public class Car { private Door door; private Engine engine; private Tire tire; public Car(PartFactory factory) { this.door = factory.createDoor(); this.engine = factory.createEngine(); this.tire = factory.createTire(); } public Door getDoor() { return door; } public Engine getEngine() { return engine; } public Tire getTire() { return tire; } } public class Client { public static void main(String[] args) { PartFactory partFactory=new BenzPartFactory(); Car benzCar=new Car(partFactory); benzCar.getDoor().open(); benzCar.getEngine().start(); benzCar.getTire().getColor(); } }
運(yùn)行結(jié)果如下:
奔馳車門開
benz車start
benz車color
跟據(jù)上面的類圖及運(yùn)行結(jié)果可以做如下分析:
BenzDoor、BenzTire和BenzEngine有很強(qiáng)的關(guān)聯(lián)關(guān)系,我們可以說一部benz車,不可能用Bmw的車門,即BmwDoor。這種很強(qiáng)的關(guān)聯(lián)關(guān)系通過BenzPartFactory進(jìn)行了很好的維護(hù)。對(duì)于客戶端來說,如上面的client類,如果客戶想要一部benz車,那么我只需要一個(gè)生產(chǎn)benz車的工廠即可,這個(gè)工廠所有的產(chǎn)品實(shí)例,都是benz車的部件。從運(yùn)行結(jié)果我們也可以看出。
試想一下,隨著這個(gè)工廠的發(fā)展,他現(xiàn)在也要生產(chǎn)Audi的車,這時(shí)我們只要增加一個(gè)audi的車門的類AudiDoor、AudiTire 、AudiEngine和AudiPartFactory就可以了,其它的類不需要做任何的修改。但客戶說,我要在車上裝一對(duì)翅膀呢,堵車時(shí)可以飛,這時(shí)我們就要對(duì)每個(gè)工廠都要增加能返回翅膀的工廠方法,要對(duì)每個(gè)工廠進(jìn)行修改,這是不符合開閉原則的。所以說抽象工廠對(duì)增加產(chǎn)品等級(jí)結(jié)構(gòu)方面是不支持開閉原則的,對(duì)于產(chǎn)品族維度(如audi車)是支持開閉原則的。
五、模式的約束
對(duì)于產(chǎn)生一個(gè)相互關(guān)聯(lián)或依賴的產(chǎn)品族適用,且支持在產(chǎn)品族方向的擴(kuò)展,不適用于產(chǎn)品等級(jí)方向的擴(kuò)展。
六、模式的變體與擴(kuò)展
1、抽像工廠提供靜態(tài)工廠方法:抽像工廠可以提供一個(gè)靜態(tài)的工廠方法,通過參數(shù)返回具體的工廠實(shí)例。
2、抽像工廠與具體工廠合并:如果在產(chǎn)品族方向上確定只有一個(gè)產(chǎn)品族,那么抽像工廠就沒有必要了,這時(shí)只需要一個(gè)具體工廠就可以了,我們可以進(jìn)一步延深,為這個(gè)具體工廠提供一個(gè)靜態(tài)方法,該方法返回自已的實(shí)例。
七、與其它模式的關(guān)系
如果只有一個(gè)產(chǎn)品等級(jí)結(jié)構(gòu),那么就是工廠方法模式了,如下圖:
如果有多個(gè)產(chǎn)品等級(jí)結(jié)構(gòu),那么抽像工廠里面的每一個(gè)工廠方法都是"工廠方法"模式。
八、模式優(yōu)缺點(diǎn)
在產(chǎn)口族方向支持開閉原則,在產(chǎn)口等級(jí)結(jié)構(gòu)方向不支持開閉原則。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
JAVA實(shí)現(xiàn)基于Tcp協(xié)議的簡(jiǎn)單Socket通信實(shí)例
本篇文章主要介紹了JAVA實(shí)現(xiàn)基于Tcp協(xié)議的簡(jiǎn)單Socket通信實(shí)例,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-01-01Java獲取Prometheus監(jiān)控?cái)?shù)據(jù)的方法實(shí)現(xiàn)
本文主要介紹了Java獲取Prometheus監(jiān)控?cái)?shù)據(jù)的方法實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-12-12淺談Mybatis中resultType為hashmap的情況
這篇文章主要介紹了淺談Mybatis中resultType為hashmap的情況,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-12-12Mybatis中的游標(biāo)查詢Cursor(滾動(dòng)查詢)
這篇文章主要介紹了Mybatis中的游標(biāo)查詢Cursor(滾動(dòng)查詢),具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-01-01上傳自己的jar包到maven中央倉(cāng)庫(kù)的快速操作方法
網(wǎng)絡(luò)上可以搜索到很多jar包到中央倉(cāng)庫(kù),但是都不是多適合自己的項(xiàng)目,于是自己動(dòng)手寫個(gè),本文檔通過sonatype上傳jar包至maven中央倉(cāng)庫(kù),Sonatype通過JIRA來管理OSSRH倉(cāng)庫(kù),具體實(shí)例代碼跟隨小編一起看看吧2021-08-08Java中批處理框架spring batch詳細(xì)介紹
這篇文章主要介紹了Java中批處理框架spring batch詳細(xì)介紹,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-07-07java?MultipartFile文件上傳重命名詳細(xì)代碼示例
在文件上傳功能開發(fā)中,為防止文件重名導(dǎo)致數(shù)據(jù)覆蓋,常見的做法是在文件名前加上UUID或時(shí)間戳來區(qū)分,這篇文章主要介紹了java?MultipartFile?multipartFile文件上傳重命名的相關(guān)資料,需要的朋友可以參考下2024-09-09