工厂模式(简单工厂、工厂方法、抽象工厂)
簡(jiǎn)單工廠(chǎng)模式
??????從設(shè)計(jì)模式的類(lèi)型上來(lái)說(shuō),簡(jiǎn)單工廠(chǎng)模式是屬于創(chuàng)建型模式,又叫做靜態(tài)工廠(chǎng)方法(StaticFactory?Method)模式,但不屬于23種GOF設(shè)計(jì)模式之一。簡(jiǎn)單工廠(chǎng)模式是由一個(gè)工廠(chǎng)對(duì)象決定創(chuàng)建出哪一種產(chǎn)品類(lèi)的實(shí)例。簡(jiǎn)單工廠(chǎng)模式是工廠(chǎng)模式家族中最簡(jiǎn)單實(shí)用的模式,可以理解為是不同工廠(chǎng)模式的一個(gè)特殊實(shí)現(xiàn)。?
簡(jiǎn)單工廠(chǎng)模式的一般結(jié)構(gòu),如圖所示:
上門(mén)2個(gè)圖片有對(duì)簡(jiǎn)單工廠(chǎng)模式的理解,來(lái)源《java與模式》
?
使用場(chǎng)景
?
工廠(chǎng)類(lèi)負(fù)責(zé)創(chuàng)建的對(duì)象比較少。
客戶(hù)端只知道傳入工廠(chǎng)類(lèi)的參數(shù),對(duì)于如何創(chuàng)建對(duì)象并不關(guān)心。
?
l?工廠(chǎng)角色
l?抽象產(chǎn)品角色
l?具體產(chǎn)品角色
?其實(shí)角色這個(gè)詞用的比較確切,能夠讓我們理解到,每個(gè)角色的不是單純地指一個(gè)類(lèi),可能是一組類(lèi)所構(gòu)成了這個(gè)角色。下面對(duì)三個(gè)角色進(jìn)行描述:
1.?工廠(chǎng)角色
工廠(chǎng)角色負(fù)責(zé)產(chǎn)品的生產(chǎn)工作。在簡(jiǎn)單工廠(chǎng)模式中,工廠(chǎng)類(lèi)是一個(gè)具體的實(shí)現(xiàn)類(lèi),在系統(tǒng)設(shè)計(jì)中工廠(chǎng)類(lèi)負(fù)責(zé)實(shí)際對(duì)象的創(chuàng)建工作。
工廠(chǎng)類(lèi)(Factory)的特點(diǎn)是:它知道系統(tǒng)中都存在哪些能夠創(chuàng)建對(duì)象的具體類(lèi)(ConcreteProduct),也知道該如何將創(chuàng)建的對(duì)象,以某種能夠屏蔽具體類(lèi)實(shí)現(xiàn)細(xì)節(jié)的方式(AbstractProduct)提供給所需要的其他角色來(lái)使用該對(duì)象提供的數(shù)據(jù)和服務(wù)。
2.抽象產(chǎn)品角色
抽象產(chǎn)品角色是具體的產(chǎn)品的抽象。抽象就是將產(chǎn)品的共性抽取出來(lái),可以直接暴露給客戶(hù)端(需要使用具體產(chǎn)品的角色),對(duì)所有的客戶(hù)端來(lái)說(shuō),從工廠(chǎng)中直接獲取到的原始產(chǎn)品的外部形態(tài)都是相同的,沒(méi)有任何的差別,包括數(shù)據(jù)和服務(wù)。這也就是說(shuō),具體客戶(hù)端應(yīng)該“秘密”掌握著某一個(gè)或一些具體產(chǎn)品的詳細(xì)資料(具體產(chǎn)品類(lèi)型、數(shù)據(jù)和服務(wù)),然后根據(jù)具體客戶(hù)端(任何一個(gè)需要使用某種具體產(chǎn)品的數(shù)據(jù)和服務(wù)的實(shí)現(xiàn)類(lèi))需要什么樣的附加數(shù)據(jù)和服務(wù),進(jìn)行類(lèi)類(lèi)型轉(zhuǎn)換后,通過(guò)借助于對(duì)應(yīng)的具體產(chǎn)品對(duì)象來(lái)完成其職責(zé)。
抽象產(chǎn)品角色,在實(shí)際系統(tǒng)中可以定義為接口或者抽象類(lèi)。
3.具體產(chǎn)品角色
具體產(chǎn)品實(shí)現(xiàn)類(lèi)一定是抽象產(chǎn)品類(lèi)的實(shí)現(xiàn)或擴(kuò)展。為了保證工廠(chǎng)類(lèi)能夠創(chuàng)建對(duì)象,工廠(chǎng)類(lèi)需要知道具體產(chǎn)品的創(chuàng)建方式,這就涉及到具體產(chǎn)品類(lèi)所提供的構(gòu)造方法,以便,可能工廠(chǎng)類(lèi)會(huì)向客戶(hù)端提供具體創(chuàng)建服務(wù)所需要的數(shù)據(jù)。例如:某個(gè)產(chǎn)品類(lèi)需要通過(guò)一個(gè)賬號(hào)才能構(gòu)造其實(shí)例,所以工廠(chǎng)類(lèi)必須根據(jù)它的創(chuàng)建需求,為客戶(hù)端提供一個(gè)帶賬號(hào)參數(shù)的生產(chǎn)方法,才能創(chuàng)建該具體產(chǎn)品類(lèi)的對(duì)象。
也就是說(shuō),工廠(chǎng)類(lèi)依賴(lài)于具體產(chǎn)品實(shí)現(xiàn)類(lèi)。同樣,客戶(hù)端類(lèi)是依賴(lài)于工廠(chǎng)類(lèi)的。
通過(guò)上述三個(gè)角色的描述,我們應(yīng)該能夠了解,系統(tǒng)中哪些類(lèi)能夠勝任上述的三個(gè)角色,并通過(guò)各類(lèi)之間的關(guān)系,通過(guò)工廠(chǎng)模式來(lái)實(shí)現(xiàn)系統(tǒng)或者某個(gè)模塊。在實(shí)際的設(shè)計(jì)過(guò)程中,可能不存在完全與上述基本簡(jiǎn)單工廠(chǎng)模式完全適應(yīng)的,需要根據(jù)具體的需求來(lái)調(diào)整簡(jiǎn)單工廠(chǎng)模式的應(yīng)用。只要能夠?qū)崿F(xiàn)系統(tǒng)的良好設(shè)計(jì),有時(shí)候變化才能滿(mǎn)足需要。
下面用一個(gè)簡(jiǎn)單的例子來(lái)說(shuō)明一下,給大家加深一下印象(例子來(lái)自于網(wǎng)絡(luò)):
運(yùn)動(dòng)員.java public interface 運(yùn)動(dòng)員 { public void 跑();public void 跳(); } 足球運(yùn)動(dòng)員.java public class 足球運(yùn)動(dòng)員 implements 運(yùn)動(dòng)員 {public void 跑(){//跑啊跑} public void 跳(){//跳啊跳} } 籃球運(yùn)動(dòng)員.java public class 籃球運(yùn)動(dòng)員 implements 運(yùn)動(dòng)員 {public void 跑(){//do nothing} public void 跳(){//do nothing} } 體育協(xié)會(huì).java public class 體育協(xié)會(huì) { public static 運(yùn)動(dòng)員 注冊(cè)足球運(yùn)動(dòng)員(){return new 足球運(yùn)動(dòng)員();} public static 運(yùn)動(dòng)員 注冊(cè)籃球運(yùn)動(dòng)員(){return new 籃球運(yùn)動(dòng)員();} }俱樂(lè)部.java public class 俱樂(lè)部 {private 運(yùn)動(dòng)員 守門(mén)員;private 運(yùn)動(dòng)員 后衛(wèi);private 運(yùn)動(dòng)員 前鋒;public void test() {this.前鋒 = 體育協(xié)會(huì).注冊(cè)足球運(yùn)動(dòng)員();this.后衛(wèi) = 體育協(xié)會(huì).注冊(cè)足球運(yùn)動(dòng)員();this.守門(mén)員 = 體育協(xié)會(huì).注冊(cè)足球運(yùn)動(dòng)員();守門(mén)員.跑();后衛(wèi).跳();} }以上就是簡(jiǎn)單工廠(chǎng)模式的一個(gè)簡(jiǎn)單實(shí)例,讀者應(yīng)該想象不用接口不用工廠(chǎng)而把具體類(lèi)暴露給客戶(hù)端的那種混亂情形吧(就好像沒(méi)了體育總局,各個(gè)俱樂(lè)部在市場(chǎng)上自己胡亂的尋找仔細(xì)需要的運(yùn)動(dòng)員),簡(jiǎn)單工廠(chǎng)就解決了這種混亂。
工廠(chǎng)方法模式
工廠(chǎng)方法模式是類(lèi)的創(chuàng)建模式,又叫虛擬構(gòu)造子(Virtual?Constructor)模式或者多態(tài)性工廠(chǎng)(Polymorphic?Factory)模式。?工廠(chǎng)方法模式的用意是定義一個(gè)創(chuàng)建產(chǎn)品對(duì)象的工廠(chǎng)接口,將實(shí)際工作推遲到子類(lèi)中。
工廠(chǎng)方法模式是簡(jiǎn)單工廠(chǎng)模式的衍生,解決了許多簡(jiǎn)單工廠(chǎng)模式的問(wèn)題。首先完全實(shí)現(xiàn)‘開(kāi)-閉?原則’,實(shí)現(xiàn)了可擴(kuò)展。其次更復(fù)雜的層次結(jié)構(gòu),可以應(yīng)用于產(chǎn)品結(jié)果復(fù)雜的場(chǎng)合。工廠(chǎng)方法模式的對(duì)簡(jiǎn)單工廠(chǎng)模式進(jìn)行了抽象。有一個(gè)抽象的Factory類(lèi)(可以是抽象類(lèi)和接口),這個(gè)類(lèi)將不在負(fù)責(zé)具體的產(chǎn)品生產(chǎn),而是只制定一些規(guī)范,具體的生產(chǎn)工作由其子類(lèi)去完成。在這個(gè)模式中,工廠(chǎng)類(lèi)和產(chǎn)品類(lèi)往往可以依次對(duì)應(yīng)。即一個(gè)抽象工廠(chǎng)對(duì)應(yīng)一個(gè)抽象產(chǎn)品,一個(gè)具體工廠(chǎng)對(duì)應(yīng)一個(gè)具體產(chǎn)品,這個(gè)具體的工廠(chǎng)就負(fù)責(zé)生產(chǎn)對(duì)應(yīng)的產(chǎn)品。?
工廠(chǎng)方法模式角色與結(jié)構(gòu)
1.抽象工廠(chǎng)(Creator)角色:是工廠(chǎng)方法模式的核心,與應(yīng)用程序無(wú)關(guān)。任何在模式中創(chuàng)建的對(duì)象的工廠(chǎng)類(lèi)必須實(shí)現(xiàn)這個(gè)接口。?
2.具體工廠(chǎng)(Concrete?Creator)角色:這是實(shí)現(xiàn)抽象工廠(chǎng)接口的具體工廠(chǎng)類(lèi),包含與應(yīng)用程序密切相關(guān)的邏輯,并且受到應(yīng)用程序調(diào)用以創(chuàng)建產(chǎn)品對(duì)象。
3.抽象產(chǎn)品(Product)角色:工廠(chǎng)方法模式所創(chuàng)建的對(duì)象的超類(lèi)型,也就是產(chǎn)品對(duì)象的共同父類(lèi)或共同擁有的接口。
4.具體產(chǎn)品(Concrete?Product)角色:這個(gè)角色實(shí)現(xiàn)了抽象產(chǎn)品角色所定義的接口。某具體產(chǎn)品有專(zhuān)門(mén)的具體工廠(chǎng)創(chuàng)建,它們之間往往一一對(duì)應(yīng)。
工廠(chǎng)方法模式的一般結(jié)構(gòu),如圖所示:
我們?cè)诓桓淖儺a(chǎn)品類(lèi)(“足球運(yùn)動(dòng)員”類(lèi)和“籃球運(yùn)動(dòng)員”類(lèi))的情況下,寫(xiě)一下工廠(chǎng)方法模式的例子:
?
運(yùn)動(dòng)員.java public interface 運(yùn)動(dòng)員 { public void 跑();public void 跳(); }足球運(yùn)動(dòng)員.java public class 足球運(yùn)動(dòng)員 implements 運(yùn)動(dòng)員 {public void 跑(){//跑啊跑}public void 跳(){//跳啊跳} }籃球運(yùn)動(dòng)員.java public class 籃球運(yùn)動(dòng)員 implements 運(yùn)動(dòng)員 {public void 跑(){//do nothing}public void 跳(){//do nothing} }體育協(xié)會(huì).java public interface 體育協(xié)會(huì) {public 運(yùn)動(dòng)員 注冊(cè)(); }足球協(xié)會(huì).java public class 足球協(xié)會(huì) implements 體育協(xié)會(huì) {public 運(yùn)動(dòng)員 注冊(cè)(){return new 足球運(yùn)動(dòng)員();} }籃球協(xié)會(huì).java public class 籃球協(xié)會(huì) implements 體育協(xié)會(huì) {public 運(yùn)動(dòng)員 注冊(cè)(){return new 籃球運(yùn)動(dòng)員();} }俱樂(lè)部.java public class 俱樂(lè)部 {private 運(yùn)動(dòng)員 守門(mén)員;private 運(yùn)動(dòng)員 后衛(wèi);private 運(yùn)動(dòng)員 前鋒;public void test() {體育協(xié)會(huì) 中國(guó)足協(xié) = new 足球協(xié)會(huì)();this.前鋒 = 中國(guó)足協(xié).注冊(cè)();this.后衛(wèi) = 中國(guó)足協(xié).注冊(cè)();守門(mén)員.跑();后衛(wèi).跳();} }?
很明顯可以看到,“體育協(xié)會(huì)”工廠(chǎng)類(lèi)變成了“體育協(xié)會(huì)”接口,而實(shí)現(xiàn)此接口的分別是“足球協(xié)會(huì)”“籃球協(xié)會(huì)”等等具體的工廠(chǎng)類(lèi)。
這樣做有什么好處呢?很明顯,這樣做就完全OCP了。如果需要再加入(或擴(kuò)展)產(chǎn)品類(lèi)(比如加多個(gè)“乒乓球運(yùn)動(dòng)員”)的話(huà)就不再需要修改工廠(chǎng)類(lèi)了,而只需相應(yīng)的再添加一個(gè)實(shí)現(xiàn)了工廠(chǎng)接口(“體育協(xié)會(huì)”接口)的具體工廠(chǎng)類(lèi)。
抽象工廠(chǎng)模式
?????? 抽象工廠(chǎng)模式是所有形態(tài)的工廠(chǎng)模式中最為抽象和最具一般性的一種形態(tài)。抽象工廠(chǎng)模式是指當(dāng)有多個(gè)抽象角色時(shí),使用的一種工廠(chǎng)模式。抽象工廠(chǎng)模式可以向客戶(hù)端提供一個(gè)接口,使客戶(hù)端在不必指定產(chǎn)品的具體的情況下,創(chuàng)建多個(gè)產(chǎn)品族中的產(chǎn)品對(duì)象。根據(jù)LSP原則,任何接受父類(lèi)型的地方,都應(yīng)當(dāng)能夠接受子類(lèi)型。因此,實(shí)際上系統(tǒng)所需要的,僅僅是類(lèi)型與這些抽象產(chǎn)品角色相同的一些實(shí)例,而不是這些抽象產(chǎn)品的實(shí)例。換言之,也就是這些抽象產(chǎn)品的具體子類(lèi)的實(shí)例。工廠(chǎng)類(lèi)負(fù)責(zé)創(chuàng)建抽象產(chǎn)品的具體子類(lèi)的實(shí)例。
?????先來(lái)認(rèn)識(shí)下什么是產(chǎn)品族:?位于不同產(chǎn)品等級(jí)結(jié)構(gòu)中,功能相關(guān)聯(lián)的產(chǎn)品組成的家族。還是讓我們用一個(gè)例子來(lái)形象地說(shuō)明一下吧。
抽象工廠(chǎng)模式中的有以下的四種角色:
抽象工廠(chǎng)(Abstract?Factory)角色:擔(dān)任這個(gè)角色的是工廠(chǎng)方法模式的核心,它是與應(yīng)用系統(tǒng)商業(yè)邏輯無(wú)關(guān)的。?
具體工廠(chǎng)(Concrete?Factory)角色:這個(gè)角色直接在客戶(hù)端的調(diào)用下創(chuàng)建產(chǎn)品的實(shí)例。這個(gè)角色含有選擇合適的產(chǎn)品對(duì)象的邏輯,而這個(gè)邏輯是與應(yīng)用系統(tǒng)的商業(yè)邏輯緊密相關(guān)的。
?抽象產(chǎn)品(Abstract?Product)角色:擔(dān)任這個(gè)角色的類(lèi)是工廠(chǎng)方法模式所創(chuàng)建的對(duì)象的父類(lèi),或它們共同擁有的接口。
具體產(chǎn)品(Concrete?Product)角色:這個(gè)角色用以代表具體的產(chǎn)品。
?Abstract?Factory模式的結(jié)構(gòu):
?
?
?
?
?
package abstractFactory;public interface KitchenFactory{public Food getFood();public TableWare getTableWare();}抽象餐具的接口定義如下所示:package abstractFactory;public interface TableWare{public String getTool();}抽象事物的接口定義如下所示:package abstractFactory;public interface Food{public String getEatable();}而具體的實(shí)現(xiàn)也非常簡(jiǎn)單,以AKitchen為例子具體工廠(chǎng)AKitchen的定義如下所示;package abstractFactory;public class AKitchenimplements KitchenFactory{public Food getFood(){return new Milk();}public TableWare getTableWare(){return new Spoon();}}具體餐具(spoon)的定義如下所示:package abstractFactory;public class Spoonimplements TableWare{ public String getTool() {return "spoon";}}具體食物(milk)的定義如下所示:package abstractFactory;public class Milkimplements Food{public String getEatable(){return "milk";}}客戶(hù)端的定義如下:package abstractFactory;public class Client{public void eat(KitchenFactory k){System.out.println("A person eat "+k.getFood().getEatable()+" with "+k.getTableWare().getTool()+"!");}public static void main(String[] args){Client client=new Client();KitchenFactory kf =new AKitchen();client.eat(kf);kf=new BKitchen();client.eat(kf);kf=new CKitchen();client.eat(kf);}}?
在以下情況下應(yīng)當(dāng)考慮使用抽象工廠(chǎng)模式:
·?一個(gè)系統(tǒng)不應(yīng)當(dāng)依賴(lài)于產(chǎn)品類(lèi)實(shí)例如何被創(chuàng)建、組合和表達(dá)的細(xì)節(jié),這對(duì)于所有形態(tài)的工廠(chǎng)模式都是重要的。
·?這個(gè)系統(tǒng)有多于一個(gè)的產(chǎn)品族,而系統(tǒng)只消費(fèi)其中某一產(chǎn)品族。
·?同屬于同一個(gè)產(chǎn)品族的產(chǎn)品是在一起使用的,這一約束必須在系統(tǒng)的設(shè)計(jì)中體現(xiàn)出來(lái)。
·?系統(tǒng)提供一個(gè)產(chǎn)品類(lèi)的庫(kù),所有的產(chǎn)品以同樣的接口出現(xiàn),從而使客戶(hù)端不依賴(lài)于實(shí)現(xiàn)。
?
?
?
?
?
總結(jié)
以上是生活随笔為你收集整理的工厂模式(简单工厂、工厂方法、抽象工厂)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Android之CSDN 牛人博客索引
- 下一篇: Android之Universal-Im