【設(shè)計(jì)模式(1):工廠模式】
寫在前面——
如果轉(zhuǎn)載請(qǐng)注明出處,謝謝大家支持
——Forward
我的微博——秦京一夢
QQ技術(shù)交流群——forTheDream(225117179)
今天,一個(gè)同學(xué)找我?guī)退鲆粋€(gè)程序(貌似是某公司的面試題哦~@_@),題目如下:
【銷售稅都是由基本稅和進(jìn)口稅構(gòu)成?;径愂巧唐穬r(jià)格的10%,書籍,食品和醫(yī)療產(chǎn)品免征基本稅。如果是進(jìn)口商品,需要征收商品價(jià)格5%的進(jìn)口稅,所有進(jìn)口商品都要征收進(jìn)口稅。
購買商品時(shí),需要打印一張收據(jù),上面會(huì)列出所有購買的商品名稱和價(jià)格(含稅),總價(jià)及所交稅的金額。銷售稅的計(jì)算公式為:t=稅率n%*單價(jià)p(注:np/100四舍五入到最接近的0.05)?!?/p>
其實(shí)題目本身并不難,作為開發(fā)人員,或許我們不能僅僅要求功能上的正確,更多的是對(duì)代碼結(jié)構(gòu)上有更高的要求,比如要求代碼清晰易懂,具有更高的復(fù)用性和擴(kuò)展性。設(shè)計(jì)模式正不正是幫助我們來達(dá)到這個(gè)目的的嗎?!
今天我們就設(shè)計(jì)模式中比較簡單而常用的一種——工廠方法來做一次學(xué)習(xí)。
工廠模式一般分為工廠方法模式(簡單工廠模式視為工廠方法模式的一種)和抽象工廠模式。下面進(jìn)行一個(gè)簡單的對(duì)比:
工廠方法模式:擁有一個(gè)產(chǎn)品抽象類,可以派生出多個(gè)具體的產(chǎn)品子類;擁有一個(gè)工廠抽象類,可以派生出多個(gè)具體的工廠子類;每個(gè)具體的工廠子類只創(chuàng)建一個(gè)具體的產(chǎn)品子類實(shí)例。抽象工廠模式:具有多個(gè)產(chǎn)品抽象類,每個(gè)抽象產(chǎn)品類可以派生出多個(gè)具體產(chǎn)品類;一個(gè)抽象工廠類,可以派生出多個(gè)具體工廠類;每個(gè)具體工廠類可以創(chuàng)建多個(gè)具體產(chǎn)品實(shí)例。
這樣的描述可以還是不夠直觀,F(xiàn)orward在做整理的時(shí)候,看到一篇博客的留言,感覺說的挺貼切的,大家感受一下——
1.簡單工廠:工廠可以創(chuàng)建同一系列的產(chǎn)品,產(chǎn)品的接口一致,但工廠就要根據(jù)參數(shù)進(jìn)行判斷到底創(chuàng)建哪種產(chǎn)品。賣早飯的張婆婆:可以做茶葉蛋,包子,稀飯
2.工廠方法:可以有多種工廠,工廠有共同的接口,一個(gè)工廠只能產(chǎn)生一種產(chǎn)品,比起簡單工廠,工廠方法就不需要判斷,耦合度低了不少。劉老板:只賣包子的包子鋪,只賣稀飯的稀飯莊
3.抽象工廠:可以產(chǎn)生多個(gè)系列的產(chǎn)品,有2個(gè)維度的產(chǎn)品。飲料店老板:可樂系列產(chǎn)品、咖啡系列產(chǎn)品,每種系列產(chǎn)品又分小杯、中杯、大杯
可能我們很快就可以作如下的結(jié)構(gòu),有一個(gè)虛基類ProductBase類,所有商品都繼承它,子類自己實(shí)現(xiàn)自己的征稅額計(jì)算方法,然后通過向ProductBaseFactoryBook傳遞商品ID來創(chuàng)建對(duì)應(yīng)商品,客戶端只是通過ProductBaseFactoryBook來創(chuàng)建所需商品(比如寫一個(gè)switch語句或者if-else來創(chuàng)建對(duì)應(yīng)商品),這樣做的好處是在一定程度上達(dá)到了對(duì)調(diào)用者屏蔽具體類的作用。
圖 1
但這樣的設(shè)計(jì)還是存在問題的,比如商店的商品越來越多,我們的ProductBaseFactoryBook的CreateProduct接口會(huì)越來越臃腫,這肯定不是我們想看到的,看來這樣的設(shè)計(jì)還是有欠妥之處,我們馬上對(duì)上面的設(shè)計(jì)做一次修改,如下圖所示——
圖 2
這里我們設(shè)計(jì)了一個(gè)工廠抽象類ProductBaseFactory和一個(gè)產(chǎn)品抽象類ProductBase,針對(duì)題目中的書本,派生出兩個(gè)類——ProductBaseFactoryBook和ProductBook,ProductBaseFactoryBook實(shí)現(xiàn)基類的ProductBase接口只負(fù)責(zé)創(chuàng)建ProductBook實(shí)例。這樣就是我們上面提到的工廠方法了。
當(dāng)我們的商店再來新的商品時(shí),我們依樣畫葫蘆,創(chuàng)建對(duì)應(yīng)的工廠A和商品A即可,而工廠A則只負(fù)責(zé)創(chuàng)建商品A。而調(diào)用者每次只需要獲取對(duì)應(yīng)工廠的CreateProduct接口就行了。但是這里我們注意到還有一個(gè)問題,商品是分進(jìn)口和非進(jìn)口的,如果采用這樣的設(shè)計(jì),同樣一種商品進(jìn)口和非進(jìn)口還是混淆在一起,不易擴(kuò)展,再改改我們的設(shè)計(jì)吧~~

圖 3
我們從ProductBase中派生出兩個(gè)虛基類ProductImport和ProductNotImport然后對(duì)應(yīng)的派生出每種商--品的進(jìn)口和非進(jìn)口類型,而我們的ProductBaseFactory則派生出兩種類型ProductBaseFactoryImport和ProductBaseFactoryNotImport兩種,在Factory類型中我們添加對(duì)應(yīng)商品的創(chuàng)建接口,如CreateProductBook、CreateProductCD等等。這樣的設(shè)計(jì)耦合度又降低了。這種設(shè)計(jì)恰恰使用了抽象工廠設(shè)計(jì)模式。
在這篇博客中,我們對(duì)設(shè)計(jì)模式中的工廠模式的幾種情況進(jìn)行了逐一設(shè)計(jì)實(shí)現(xiàn),對(duì)工廠模式也基本有了一個(gè)比較清楚的認(rèn)識(shí)。總結(jié)一下——
設(shè)計(jì)模式的使用籠統(tǒng)來說使得代碼整體變得更好。而其中的工廠模式的使用則具有如下有點(diǎn):
1、代碼結(jié)構(gòu)更加清晰易懂,利用面向?qū)ο缶幊讨械姆庋b、繼承和多態(tài)特性,對(duì)調(diào)用者屏蔽了對(duì)象創(chuàng)建過程,使得具體的對(duì)象創(chuàng)建更加簡單,調(diào)用者可以將更多的注意力放到對(duì)象的實(shí)際調(diào)用而不用再糾結(jié)于對(duì)象實(shí)例化的繁瑣工作中;
2、工廠模式的使用大大降低了代碼耦合度,調(diào)用者只知道工廠和對(duì)象類本身的存在,其中實(shí)例化過程涉及的其他類,對(duì)調(diào)用者來說幾乎是透明的。
參考博客:
http://blog.csdn.net/hguisu/article/details/7505909
http://blog.csdn.net/zhengzhb/article/details/7359385
http://blog.csdn.net/zhengzhb/article/details/7348707
愛華網(wǎng)



