C#設(shè)計(jì)模式編程之抽象工廠模式新解_第1頁(yè)
C#設(shè)計(jì)模式編程之抽象工廠模式新解_第2頁(yè)
C#設(shè)計(jì)模式編程之抽象工廠模式新解_第3頁(yè)
C#設(shè)計(jì)模式編程之抽象工廠模式新解_第4頁(yè)
C#設(shè)計(jì)模式編程之抽象工廠模式新解_第5頁(yè)
已閱讀5頁(yè),還剩13頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

1、概述在軟件系統(tǒng)中,經(jīng)常面臨著“一系列相互依賴的對(duì)象”的創(chuàng)建工作;同時(shí)由于需求的變化,往往存在著更多系列對(duì)象的 創(chuàng)建工作。如何應(yīng)對(duì)這種變化?如何繞過(guò)常規(guī)的對(duì)象的創(chuàng)建方法(new),提供一種“封裝機(jī)制”來(lái)避免客戶程序和這種“多系列具體對(duì)象創(chuàng)建工作”的緊耦合? 這就是我們要說(shuō)的抽象工廠模式。意圖提供一個(gè)創(chuàng)建一系列相關(guān)或相互依賴對(duì)象的接口,而無(wú)需指定它們具體的類。 模型圖邏輯模型:物理模型:生活中的例子抽象工廠的目的是要提供一個(gè)創(chuàng)建一系列相關(guān)或相互依賴 對(duì)象的接口,而不需要指定它們具體的類。這種模式可以汽車制造廠所使用的金屬?zèng)_壓設(shè)備中找到。這種沖壓設(shè)備可以制造汽車車身部件。同樣的機(jī)械用于沖壓不同 的車

2、型的右邊車門(mén)、左邊車門(mén)、右前擋泥板、左前擋泥板和引擎罩等等。通過(guò)使用轉(zhuǎn)輪來(lái)改變沖壓盤(pán),這個(gè)機(jī)械產(chǎn)生的具體類可以在三分鐘內(nèi)改變。抽象工廠之新解虛擬案例中國(guó)企業(yè)需要一項(xiàng)簡(jiǎn)單的 財(cái)務(wù)計(jì)算:每月月底,財(cái)務(wù)人員要計(jì)算員工的工資。員工的工資 = (基本工資 + 獎(jiǎng)金 - 個(gè)人所得稅)。這是一個(gè)放之四海皆準(zhǔn)的運(yùn)算法則。為了簡(jiǎn)化系統(tǒng),我們假設(shè)員工基本工資總是4000美金。中國(guó)企業(yè)獎(jiǎng) 金和個(gè)人所得稅的計(jì)算規(guī)則是:獎(jiǎng)金 = 基本工資(4000) * 10%個(gè)人所得稅 = (基本工資 + 獎(jiǎng)金) * 40%我們現(xiàn)在要為此構(gòu)建一個(gè)軟件系統(tǒng)(代號(hào)叫softo),滿足中國(guó)企業(yè)的需 求。案例分析獎(jiǎng)金(bonus)、個(gè)人所得

3、稅(tax)的計(jì)算是softo系統(tǒng)的業(yè)務(wù)規(guī)則(service)。 工資的計(jì)算(calculator)則調(diào)用業(yè)務(wù)規(guī)則(service)來(lái)計(jì)算員工的實(shí)際工資。工資的計(jì)算作為業(yè)務(wù)規(guī)則的前端(或者客 戶端client)將提供給最終使用該系統(tǒng)的用戶(財(cái)務(wù)人員)使用。針對(duì)中國(guó)企業(yè)為系統(tǒng)建模根據(jù)上面的分析,為 softo系統(tǒng)建模如下:則業(yè)務(wù)規(guī)則service類的代碼如下:using system;namespace chinesesalary /*/ summary / 公用的常量 / /summary public class constant public static double base_sala

4、ry = 4000; using system;namespace chinesesalary /*/ summary / 計(jì)算中國(guó)個(gè)人獎(jiǎng)金 / /summary public class chinesebonus public double calculate() return constant.base_salary * 0.1; 客戶端的調(diào)用代碼:using system;namespace chinesesalary /*/ summary / 計(jì)算中國(guó)個(gè)人所得稅 / /summary public class chinesetax public double calculate()

5、return (constant.base_salary + (constant.base_salary * 0.1) * 0.4; 運(yùn)行程序,輸入的結(jié)果如下:chinese salary is:2640針對(duì)美國(guó)企業(yè)為系統(tǒng)建模 為了拓展國(guó)際市場(chǎng),我們要把該系統(tǒng)移植給美國(guó)公司使用。 美國(guó)企業(yè)的工資計(jì)算同樣是: 員工的工資 = 基本工資 + 獎(jiǎng)金 - 個(gè)人所得稅。 但是他們的獎(jiǎng)金和個(gè)人所得稅的計(jì)算規(guī)則不同于中國(guó)企業(yè):美國(guó)企業(yè)獎(jiǎng)金和個(gè)人所得稅的計(jì)算規(guī)則是:獎(jiǎng)金 = 基本工資 * 15 %個(gè)人所得稅 = (基本工資 * 5% + 獎(jiǎng)金 * 25%)根據(jù)前面為中國(guó)企業(yè)建模經(jīng) 驗(yàn),我們僅僅將chinese

6、tax、chinesebonus修改為americantax、americanbonus。 修改后的模型如下: 則業(yè)務(wù)規(guī)則service類的代碼如下:using system;namespace americansalary /*/ summary / 公用的常量 / /summary public class constant public static double base_salary = 4000; using system;namespace americansalary /*/ summary / 計(jì)算美國(guó)個(gè)人獎(jiǎng)金 / /summary public class american

7、bonus public double calculate() return constant.base_salary * 0.1; using system;namespace americansalary /*/ summary / 計(jì)算美國(guó)個(gè)人所得稅 / /summary public class americantax public double calculate() return (constant.base_salary + (constant.base_salary * 0.1) * 0.4; 客戶端的調(diào)用代碼:using system;namespace americansa

8、lary /*/ summary / 客戶端程序調(diào)用 / /summary public class calculator public static void main(string args) americanbonus bonus = new americanbonus(); double bonusvalue = bonus.calculate(); americantax tax = new americantax(); double taxvalue = tax.calculate(); double salary = 4000 + bonusvalue - taxvalue; c

9、onsole.writeline(american salary is: + salary); console.readline(); 運(yùn)行程序,輸入 的結(jié)果如下:american salary is:2640整合成通用系統(tǒng)讓我們回顧一下該系 統(tǒng)的發(fā)展歷程:最初,我們只考慮將softo系統(tǒng)運(yùn)行于中國(guó)企業(yè)。但隨著maxdo公司業(yè)務(wù)向海外拓展, maxdo需要將該系統(tǒng)移植給美國(guó)使用。移植時(shí),maxdo不得不拋棄中國(guó)企業(yè)的業(yè)務(wù)規(guī)則類chinesetax和 chinesebonus, 然后為美國(guó)企業(yè)新建兩個(gè)業(yè)務(wù)規(guī)則類: americantax,americanbonus。最后修改了業(yè)務(wù)規(guī)則調(diào)用calc

10、ulator類。結(jié)果我們發(fā)現(xiàn):每當(dāng)softo 系統(tǒng)移植的時(shí)候,就拋棄原來(lái)的類?,F(xiàn)在,如果中國(guó)聯(lián)想集團(tuán)要購(gòu)買該系統(tǒng),我們不得不再次拋棄americantax,americanbonus,修改回 原來(lái)的業(yè)務(wù)規(guī)則。一個(gè)可以立即想到的做法就是在系統(tǒng)中保留所有業(yè)務(wù)規(guī)則模型,即保留中國(guó)和美國(guó)企業(yè)工資運(yùn)算規(guī)則。通過(guò)保留中國(guó)企業(yè)和美國(guó)企業(yè)的業(yè)務(wù)規(guī)則模型,如果該系統(tǒng)在美國(guó)企業(yè)和中國(guó)企業(yè)之間切換時(shí),我 們僅僅需要修改caculator類即可。讓移植工作更簡(jiǎn)單前面系統(tǒng)的整合問(wèn)題在于:當(dāng)系統(tǒng)在客戶在美國(guó)和中國(guó)企業(yè)間切換時(shí)仍然需要修改caculator代碼。一個(gè)維護(hù)性良 好的系統(tǒng)應(yīng)該遵循“開(kāi)閉原則”。即:封閉對(duì)原來(lái)代碼

11、的修改,開(kāi)放對(duì)原來(lái)代碼的擴(kuò)展(如類的繼承,接口的實(shí)現(xiàn))我們發(fā)現(xiàn)不論是中國(guó)企業(yè)還 是美國(guó)企業(yè),他們的業(yè)務(wù)運(yùn)規(guī)則都采用同樣的計(jì)算接口。 于是很自然地想到建立兩個(gè)業(yè)務(wù)接口類tax,bonus,然后讓americantax、americanbonus和chinesetax、 chinesebonus分別實(shí)現(xiàn)這兩個(gè)接口, 據(jù)此修正后的模型如下: 此時(shí)客戶端代碼如下:using system;namespace interfacesalary /*/ summary / 客戶端程序調(diào)用 / /summary public class calculator public static void main(s

12、tring args) bonus bonus = new chinesebonus(); double bonusvalue = bonus.calculate(); tax tax = new chinesetax(); double taxvalue = tax.calculate(); double salary = 4000 + bonusvalue - taxvalue; console.writeline(chinaese salary is: + salary); console.readline(); 為業(yè)務(wù)規(guī)則增加工廠方法然而,上面增加的接口幾乎沒(méi)有解決任何問(wèn)題,因?yàn)楫?dāng)系統(tǒng)

13、的客戶在美國(guó)和中國(guó)企業(yè)間切換時(shí)caculator代碼仍然需要修改。 只不過(guò)修改少了兩處,但是仍然需要修改chinesebonus,chinesetax部分。致命的問(wèn)題是:我們需要將這個(gè)移植工作轉(zhuǎn)包給一個(gè)叫 hippo的軟件公司。 由于版權(quán)問(wèn)題,我們并未提供softo系統(tǒng)的源碼給hippo公司,因此hippo公司根本無(wú)法修改calculator,導(dǎo)致實(shí)際上移植工作無(wú)法進(jìn)行。為此,我們考慮增加一個(gè)工具類(命名為factory),代碼如下:using system;namespace factorysalary /*/ summary / factory類 / /summary public cla

14、ss factory public tax createtax() return new chinesetax(); public bonus createbonus() return new chinesebonus(); 修改后的客戶端代碼:using system;namespace factorysalary /*/ summary / 客戶端程序調(diào)用 / /summary public class calculator public static void main(string args) bonus bonus = new factory().createbonus(); dou

15、ble bonusvalue = bonus.calculate(); tax tax = new factory().createtax(); double taxvalue = tax.calculate(); double salary = 4000 + bonusvalue - taxvalue; console.writeline(chinaese salary is: + salary); console.readline(); 不錯(cuò),我們解決了一個(gè)大問(wèn)題,設(shè)想一下:當(dāng)該系統(tǒng)從中國(guó)企業(yè)移植到美國(guó)企業(yè)時(shí),我們現(xiàn)在需要做什么?答案是: 對(duì)于caculator類我們什么也不用做。我們需要

16、做的是修改factory類,修改結(jié)果如下:using system;namespace factorysalary /*/ summary / factory類 / /summary public class factory public tax createtax() return new americantax(); public bonus createbonus() return new americanbonus(); 為系統(tǒng)增加抽象工廠方法很顯然,前面的解決方案帶來(lái)了一個(gè)副作用:就是系統(tǒng)不但增加了新的類factory,而且當(dāng) 系統(tǒng)移植時(shí),移植工作僅僅是轉(zhuǎn)移到factory類上,工作

17、量并沒(méi)有任何縮減,而且還是要修改系統(tǒng)的源碼。 從factory類在系統(tǒng)移植時(shí)修改的內(nèi)容我們可以看出: 實(shí)際上它是專屬于美國(guó)企業(yè)或者中國(guó)企業(yè)的。名稱上應(yīng)該叫americanfactory,chinesefactory更合適.解決方 案是增加一個(gè)抽象工廠類abstractfactory,增加一個(gè)靜態(tài)方法,該方法根據(jù)一個(gè)配置文件(app.config或者web.config) 一個(gè)項(xiàng)(比如factoryname)動(dòng)態(tài)地判斷應(yīng)該實(shí)例化哪個(gè)工廠類,這樣,我們就把移植工作轉(zhuǎn)移到了對(duì)配置文件的修改。修改后的模型和代碼:抽象工廠類的代碼如下:using system;using system.reflecti

18、on;namespace abstractfactory /*/ summary / abstractfactory類 / /summary public abstract class abstractfactory public static abstractfactory getinstance() string factoryname = constant.str_factoryname.tostring(); abstractfactory instance; if(factoryname = chinesefactory) instance = new chinesefactory(

19、); else if(factoryname = americanfactory) instance = new americanfactory(); else instance = null; return instance; public abstract tax createtax(); public abstract bonus createbonus(); 配置文件:?xml version=1.0 encoding=utf-8 ?configuration appsettings add key=factoryname value=americanfactory/add /apps

20、ettings/configuration 采用上面的解決方案,當(dāng)系統(tǒng)在美國(guó)企業(yè)和中國(guó)企業(yè)之間切換時(shí),我們需要做什么移植工作?答案是: 我們僅僅需要修改配置文件,將factoryname的值改為american。修改配置文件的工作很簡(jiǎn)單,只要寫(xiě)一篇幅配置文檔說(shuō)明 書(shū)提供給移植該系統(tǒng)的團(tuán)隊(duì)(比如hippo公司) 就可以方便地切換使該系統(tǒng)運(yùn)行在美國(guó)或中國(guó)企業(yè)。最后的修正(不是最終方案) 前面的解決方案幾乎很完美,但是還有一點(diǎn)瑕疵,瑕疵雖小,但可能是致命的??紤]一下,現(xiàn)在日本nec公司決定購(gòu)買該系統(tǒng),nec公司 的工資的運(yùn)算規(guī)則遵守的是日本的法律。如果采用上面的系統(tǒng)構(gòu)架,這個(gè)移植我們要做哪些工作呢?

21、1. 增加新的業(yè)務(wù)規(guī)則類japanesetax,japanesebonus分別實(shí)現(xiàn)tax和bonus接口。2. 修改abstractfactory的getinstance方法,增加else if(factoryname.equals(japanese).注意: 系統(tǒng)中增加業(yè)務(wù)規(guī)則類不是模式所能解決的,無(wú)論采用什么設(shè)計(jì)模式,japanesetax,japanesebonus總是少不了的。(即增加了新系列產(chǎn)品)我們真正不能接受的是:我們?nèi)匀恍抟薷南到y(tǒng)中原來(lái)的類(abstractfactory)。前面提到過(guò)該系統(tǒng)的移植工作,我們可 能轉(zhuǎn)包給一個(gè)叫hippo的軟件公司。 為了維護(hù)版權(quán),未將該系統(tǒng)的源

22、碼提供給hippo公司,那么hippo公司根本無(wú)法修改abstractfactory,所以系統(tǒng)移植其實(shí)無(wú)從談起,或者 說(shuō)系統(tǒng)移植總要開(kāi)發(fā)人員親自參與。解決方案是將抽象工廠類中的條件判斷語(yǔ)句,用.net中發(fā)射機(jī)制代替,修改如下:using system;using system.reflection;namespace abstractfactory /*/ summary / abstractfactory類 / /summary public abstract class abstractfactory public static abstractfactory getinstance()

23、string factoryname = constant.str_factoryname.tostring(); abstractfactory instance; if(factoryname != ) instance = (abstractfactory)assembly.load(factoryname).createinstance(factoryname); else instance = null; return instance; public abstract tax createtax(); public abstract bonus createbonus(); 這樣,

24、在我們編寫(xiě)的代碼中就不會(huì)出現(xiàn) chinese,american,japanese等這樣的字眼了。小結(jié)最后那幅圖是最終版的系統(tǒng)模型圖。我們發(fā)現(xiàn)作為客戶端角色的calculator僅僅依賴抽象類, 它不必去理解中國(guó)和美國(guó)企業(yè)具體的業(yè)務(wù)規(guī)則如何實(shí)現(xiàn),calculator面對(duì)的僅僅是業(yè)務(wù)規(guī)則接口tax和bonus。softo系 統(tǒng)的實(shí)際開(kāi)發(fā)的分工可能是一個(gè)團(tuán)隊(duì)專門(mén)做業(yè)務(wù)規(guī)則,另一個(gè)團(tuán)隊(duì)專門(mén)做前端的業(yè)務(wù)規(guī)則組裝。 抽象工廠模式有助于這樣的團(tuán)隊(duì)的分工: 兩個(gè)團(tuán)隊(duì)通訊的約定是業(yè)務(wù)接口,由抽象工廠作為紐帶粘合業(yè)務(wù)規(guī)則和前段調(diào)用,大大降低了模塊間的耦合性,提高了團(tuán)隊(duì)開(kāi)發(fā)效率。完完全全 地理解抽象工廠模式的意義非

25、常重大,可以說(shuō)對(duì)它的理解是你對(duì)oop理解上升到一個(gè)新的里程碑的重要標(biāo)志。 學(xué)會(huì)了用抽象工廠模式編寫(xiě)框架類,你將理解oop的精華:面向接口編程。應(yīng)對(duì)“新對(duì)象”抽象工廠模式主要在于應(yīng)對(duì)“新系列”的需求變化。其缺點(diǎn)在于難于應(yīng)付“新對(duì)象”的需求變動(dòng)。如果在開(kāi) 發(fā)中出現(xiàn)了新對(duì)象,該如何去解決呢?這個(gè)問(wèn)題并沒(méi)有一個(gè)好的答案,下面我們看一下李建忠老師的回答:“gof設(shè)計(jì)模式中提出過(guò)一種 解決方法,即給創(chuàng)建對(duì)象的操作增加參數(shù),但這種做法并不能令人滿意。事實(shí)上,對(duì)于新系列加新對(duì)象,就我所知,目前還沒(méi)有完美的做法,只有一些演化的思路, 這種變化實(shí)在是太劇烈了,因?yàn)橄到y(tǒng)對(duì)于新的對(duì)象是完全陌生的?!?實(shí)現(xiàn)要點(diǎn)抽象工廠

26、將產(chǎn)品對(duì)象的創(chuàng)建延遲到它的具體工廠的子類。 如果沒(méi)有應(yīng)對(duì)“多系列對(duì)象創(chuàng)建”的需求變化,則沒(méi)有必要使用抽象工廠模式,這時(shí)候使用簡(jiǎn)單的靜態(tài)工廠完全可以。系列對(duì)象指的是這 些對(duì)象之間有相互依賴、或作用的關(guān)系,例如游戲開(kāi)發(fā)場(chǎng)景中的“道路”與“房屋”的依賴,“道路”與“地道”的依賴。抽象工廠模式經(jīng)常 和工廠方法模式共同組合來(lái)應(yīng)對(duì)“對(duì)象創(chuàng)建”的需求變化。通常在運(yùn)行時(shí)刻創(chuàng)建一個(gè)具體工廠類的實(shí)例,這一具體工廠的創(chuàng)建具有特定實(shí)現(xiàn)的 產(chǎn)品對(duì)象,為創(chuàng)建不同的產(chǎn)品對(duì)象,客戶應(yīng)使用不同的具體工廠。 l 把工廠作為單件,一個(gè)應(yīng)用中一般每個(gè)產(chǎn)品系列只需一個(gè)具體工廠的實(shí)例,因此,工廠通常最好實(shí)現(xiàn)為一個(gè)單件模式。創(chuàng)建產(chǎn)品,抽象工廠僅

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論