抽象工厂+反射=反射工厂
在我的上一篇文章(疑惑?改良?從簡(jiǎn)單工廠到工廠方法)中,詳細(xì)論述了創(chuàng)建模式中簡(jiǎn)單工廠到工廠方法的演變過程,并試圖結(jié)合工廠方法的設(shè)計(jì)以及.net中的反射機(jī)制之所長(zhǎng),改良出一種新型的工廠—反射工廠,這當(dāng)然不是我的首創(chuàng),經(jīng)典的PetShop 中便有此工廠的身影。本文嘗試按照前篇文章的思路,借著工廠方法到抽象工廠的演變過程而繼續(xù)對(duì)抽象工廠進(jìn)行改良,文章中的思想僅代表了作者當(dāng)時(shí)的觀點(diǎn),有欠妥的地方,還請(qǐng)各位不吝賜教。
工廠模式
前面的文章提到了簡(jiǎn)單工廠和工廠方法其實(shí)是一碼事,他們完成了將客戶對(duì)產(chǎn)品功能的使用與創(chuàng)建具體產(chǎn)品職責(zé)的分割,不同的只不過是他們實(shí)現(xiàn)方式上的差異,工廠方法利用更加優(yōu)雅的多態(tài)性取代了相對(duì)ugly的switch case…語(yǔ)句,從而很好的體現(xiàn)了設(shè)計(jì)原則中的OCP原則,此文章將不再?gòu)?qiáng)調(diào)這種實(shí)現(xiàn)上的差異性,而更多的強(qiáng)調(diào)兩者之間設(shè)計(jì)思路上的共性,并將這種共性統(tǒng)稱成為工廠模式,從而進(jìn)一步與抽象工廠進(jìn)行對(duì)比。
工廠的使用,選擇的過程
工廠模式的使用,實(shí)際上是客戶(產(chǎn)品的消費(fèi)者)對(duì)于產(chǎn)品選擇的過程,對(duì)于實(shí)現(xiàn)了相同功能的產(chǎn)品來(lái)講,客戶更加關(guān)心的是產(chǎn)品間的差異性,而工廠的作用則是將產(chǎn)品的生產(chǎn)過程封裝,根據(jù)客戶的要求直接返回客戶需要的產(chǎn)品。注意,工廠只是隱藏了產(chǎn)品的生產(chǎn)過程,但是并沒有剝奪客戶選擇的權(quán)利,那么客戶的這個(gè)選擇過程又是如何體現(xiàn)的呢?在簡(jiǎn)單工廠中,客戶通過參數(shù)的形式告訴工廠需要什么樣的產(chǎn)品,而在工廠方法中,客戶通過對(duì)工廠的選擇代替了直接對(duì)產(chǎn)品的選擇,注意到工廠方法中一個(gè)工廠只有一個(gè)Create方法,也就是說一個(gè)工廠只負(fù)責(zé)生產(chǎn)一種產(chǎn)品,那么你選擇了相應(yīng)的工廠也就等同于你選擇了對(duì)應(yīng)的產(chǎn)品。就連改良后的反射工廠也沒有消去對(duì)產(chǎn)品的選擇,只不過是將這種選擇外化(外化到配置文件中,從而使得對(duì)代碼的改動(dòng)最小)。可以說,正是由于產(chǎn)品間的差異性帶給了客戶選擇的權(quán)利,這種權(quán)利是不應(yīng)當(dāng)被工廠取代的,那么工廠模式的價(jià)值又在哪里呢?答案是抽象與封裝,工廠模式將由于客戶的不同選擇而可能導(dǎo)致的對(duì)已知事物的影響降到最低,途徑是通過抽象產(chǎn)品取代具體產(chǎn)品,使得客戶依賴于抽象(越抽象的東西越穩(wěn)定),同時(shí)將客戶的選擇封裝到一處,隔離與具體產(chǎn)品間的依賴。
工廠模式與抽象工廠
前面說了這么多無(wú)關(guān)的,為得是做好鋪墊,更加有益于對(duì)下文的理解,OK,終于該說說從工廠模式到抽象工廠的轉(zhuǎn)變了,先來(lái)對(duì)比兩張類圖:
?工廠方法(Factory Method)
抽象工廠(Abstract Factory)
從圖中我們能夠看到哪些差異?
最明顯的一點(diǎn)就是在工廠方法的類關(guān)系圖中只有一類產(chǎn)品,他們實(shí)現(xiàn)了一個(gè)統(tǒng)一的接口,而抽象工廠有多個(gè)類別的產(chǎn)品,他們分別實(shí)現(xiàn)了不同的功能(多個(gè)接口)。其次的一點(diǎn)差別就是工廠本身所具有的方法數(shù)量不同,這點(diǎn)差異其實(shí)也是由第一點(diǎn)所導(dǎo)致的,工廠需要有生產(chǎn)不同類別產(chǎn)品的功能,如果抽象工廠中的產(chǎn)品的功能簡(jiǎn)化到一個(gè),也便成為了工廠方法。
引出類別的概念,類別是指具有相同功能的一類產(chǎn)品的總稱。
再來(lái)看選擇的過程,在工廠方法中,客戶關(guān)心的只不過是實(shí)現(xiàn)同一樣功能的不同產(chǎn)品間的差異,這是一個(gè)一維選擇的過程。
1?????????????IFactory?factory?=?new?FactoryA();?//選擇了工廠即選擇了產(chǎn)品2?????????????IProduct?productA?=?factory.Create();?//工廠只有一個(gè)Create方法,只能生產(chǎn)一種產(chǎn)品
而在抽象工廠中,客戶首先要考慮的是需要哪一樣功能,其次要考慮才是產(chǎn)品間的差異。也就是說這是一個(gè)二維選擇的過程。
1?????????????IFactory?factory?=?new?FactoryA();?//選擇了某個(gè)具體工廠2?????????????IProduct?productA?=?factory.CreateProductA();?//工廠具有多個(gè)Create方法,這里選擇了其中的一個(gè)
由于產(chǎn)品類別的增加而導(dǎo)致客戶在考慮產(chǎn)品間差異的同時(shí)還要考慮產(chǎn)品間功能的差異,這種二維選擇的過程才是工廠方法與抽象工廠之間的本質(zhì)區(qū)別。
舉個(gè)肯德基與麥當(dāng)勞的例子,假設(shè)原來(lái)只有一家快餐店叫做麥當(dāng)勞,提供的食物(具體產(chǎn)品)有漢堡、可樂、薯?xiàng)l,它們都可以滿足你吃東西(抽象接口)的需求,那么你想吃快餐的時(shí)候,唯一的選擇就在于吃什么,是一維選擇,現(xiàn)在又開了一家快餐店叫做肯德基,同樣供應(yīng)漢堡、可樂和薯?xiàng)l,那么現(xiàn)在你若打算吃快餐,除了考慮吃什么外,還要考慮去哪里吃--肯德基還是麥當(dāng)勞?這便是二維的選擇。通過橫向與縱向的選擇才能最終鎖定你要的產(chǎn)品。?
引入系列的概念,相互間具有差異的同一類別的產(chǎn)品稱為不同的系列,如肯德基和麥當(dāng)勞就是兩個(gè)不同的系列。
這種選擇的區(qū)別帶來(lái)的另外一個(gè)后果就是產(chǎn)品間的差異(系列間的差異)變?yōu)榭蛻舻拇我x擇,而客戶主要的精力放在了功能的選擇上(類別的選擇)。
我們結(jié)合實(shí)例來(lái)看看抽象工廠的一般設(shè)計(jì)及實(shí)現(xiàn)
客戶調(diào)用代碼
2?????????????IHamburger?hamburger?=?factory.CreateHamburger();?//選擇吃漢堡
可以看到系列間的選擇由工廠的選擇來(lái)替代,而類別間的選擇實(shí)際上就是工廠內(nèi)不同類別產(chǎn)品創(chuàng)建方法的選擇。那么如此這般設(shè)計(jì)是否有依據(jù)呢?我們?yōu)槭裁床粚⒐S設(shè)計(jì)成為漢堡工廠,可樂工廠和薯?xiàng)l工廠呢?這其實(shí)是剛接觸抽象工廠的人經(jīng)常陷入的誤區(qū),這個(gè)問題的關(guān)鍵在于需求!需求是來(lái)自于客戶的,工廠的設(shè)計(jì)取決于客戶怎樣使用產(chǎn)品。在這個(gè)例子中,之所以要將漢堡、可樂和薯?xiàng)l設(shè)計(jì)為類別而不是系列,首先是因?yàn)樗麄儗?duì)于客戶有不同的功能,例如漢堡可以充饑,薯?xiàng)l可以解饞、可樂可以解渴,任何一個(gè)客戶希望走進(jìn)一家店(無(wú)論是肯德基還是麥當(dāng)勞)都能夠得到上面的這三種功能,這才是客戶真正的需求!如果客戶選擇走進(jìn)了麥當(dāng)勞,那么他就永遠(yuǎn)不會(huì)吃到肯德基的食品。這里有點(diǎn)繞可能需要多想一下,再舉個(gè)例子幫助理解,比如星際爭(zhēng)霸游戲,里面有三個(gè)種族,每個(gè)種族的兵營(yíng)都能生產(chǎn)三種兵,如何選定類別與系列?拋開游戲的設(shè)計(jì)來(lái)講,從用戶的角度出發(fā),我們還是會(huì)把系列對(duì)應(yīng)成種族,那是因?yàn)槿魏我粋€(gè)玩家進(jìn)入游戲后,都希望能夠體驗(yàn)三個(gè)不同的兵種所具有的不同能力,而不是希望擁有一個(gè)能夠制造出所有三個(gè)種族一級(jí)兵的兵營(yíng)。反過來(lái)講,用戶每次進(jìn)入游戲只可能選擇一個(gè)種族,如果他這次選擇了蟲族,那么他就永遠(yuǎn)不可能生產(chǎn)出機(jī)槍兵。
最后再將上面提到的種種概念進(jìn)行一下總結(jié)
類別 = 接口 = 抽象產(chǎn)品 = 具體產(chǎn)品所具有的共同功能,通過采用工廠的某個(gè)具體方法來(lái)體現(xiàn)選擇。
系列 = 抽象工廠 = 同一類別間不同產(chǎn)品的差異,通過對(duì)實(shí)例化某個(gè)具體工廠來(lái)體現(xiàn)選擇。
反射機(jī)制實(shí)現(xiàn)選擇邏輯,關(guān)于工廠的工廠
有人的地方就有恩怨,有恩怨的地方就有江湖,人就是江湖,你怎么退出?
有選擇的地方就有工廠,由工廠的地方就有反射,選擇就是反射,你怎么設(shè)計(jì)?
呵呵… 開個(gè)玩笑,其實(shí)上面所寫的幾段廢話就是為了論證這一個(gè)觀點(diǎn),有選擇的地方就可以反射。看看我是如何把工廠方法改良成反射工廠的,既然工廠方法是一維的選擇可以反射,那么對(duì)于抽象工廠這個(gè)二維的選擇自然更不在話下,仔細(xì)觀察工廠的選擇過程。
1?????????????AbstractFactory?factory?=?new?McDFactory();?//選擇去麥當(dāng)勞吃2?????????????IHamburger?hamburger?=?factory.CreateHamburger();?//選擇吃漢堡
發(fā)現(xiàn)選擇分別是針對(duì)工廠的選擇以及方法的選擇,然而對(duì)于工廠內(nèi)部方法的選擇不適用于反射機(jī)制,因?yàn)椴煌姆椒▽?shí)現(xiàn)了不同的功能,相互間沒有統(tǒng)一的接口,何談反射,那么反射自然就只能放在對(duì)于工廠的選擇上--它們都繼承自抽象工廠。于是我們建立一個(gè)反射工廠用來(lái)動(dòng)態(tài)生成需要的具體工廠,即工廠的工廠。話說起來(lái)別扭,還是看圖。
?
這里新添加的FFactory就是反射工廠 ,對(duì)于反射工廠來(lái)說,Abstract Factory就是抽象產(chǎn)品,FactoryA和FactoryB是相應(yīng)的具體產(chǎn)品。
1?????<appSettings>2?????????<add?key="factoryName"?value="FactoryA"/>
3?????</appSettings>
反射工廠
1?????????public?static?IFactory?CreateFactory()2?????????{?
3?????????????//從配置文件中讀取需要實(shí)例化的工廠
4?????????????string?factoryName?=?ConfigurationSettings.AppSettings["factoryName"].ToString();
5?
6?????????????AbstractFactory?factory;
7?????????????factory?=?(AbstractFactory)Assembly.Load("Abstract?Factory").CreateInstance("Abstract_Factory.ImproveFactory."?+?factoryName);
8?????????????return?factory;
9?????????}
?客戶使用
1?????????public?void?Run()2?????????{
3?????????????AbstractFactory factory?=?FFactory.CreateFactory();//生產(chǎn)工廠的工廠,采用反射機(jī)制
4?????????????IProduct1?product1?=?factory.CreateProduct1();?
5?????????????IProduct2?product2?=?factory.CreateProduct2();?
6?????????????
7?????????????product1.DoTask1();
8?????????????product2.DoTask2();
9?????????}
補(bǔ)充
抽象工廠的使用除了對(duì)多系列多類別的應(yīng)用外,還有一點(diǎn)很重要的原則,即它的一系列的產(chǎn)品總是在一起使用的,只有這樣才更能體現(xiàn)出抽象工廠的價(jià)值,關(guān)于這點(diǎn)我會(huì)在下一篇中通過與Builder模式作對(duì)比來(lái)闡述兩者間的相同與異同。
總結(jié)
以上是生活随笔為你收集整理的抽象工厂+反射=反射工厂的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 从简单工厂到工厂方法
- 下一篇: 机房收费系统=三层+设计模式