|
設(shè)計(jì)模式&重整技術(shù)運(yùn)用實(shí)例 作者: 點(diǎn)空間 陳國(guó)生 首先,我們從一個(gè)設(shè)計(jì)模式說(shuō)起:Facade 外觀模式。我們來(lái)談?wù)勥@個(gè)模式,這個(gè)模式的用途是將一個(gè)子系統(tǒng)內(nèi)部的眾多對(duì)象統(tǒng)一起來(lái),產(chǎn)生新的接口出來(lái)。這讓我想到我們中國(guó)有句成語(yǔ)叫:老干新枝。這個(gè)意義是,老干已經(jīng)失去了活力,但為了生存下去,必須產(chǎn)生新的枝芽,這跟一個(gè)已經(jīng)僵化的系統(tǒng)一樣,我們無(wú)法期望從原來(lái)的枝長(zhǎng)出葉子,所以只好另長(zhǎng)新芽。 如果一個(gè)系統(tǒng)已經(jīng)糾成一團(tuán),如左圖般的狀態(tài),再繼續(xù)擴(kuò)充功能,或更動(dòng)系統(tǒng)功能,那無(wú)疑的是雪上加霜,加速系統(tǒng)的走向死亡之路。由于系統(tǒng)內(nèi)部的對(duì)象交互影響,只要移動(dòng)部分的功能,Client 端的使用接口勢(shì)必要跟著改變,繼續(xù)使用這樣的系統(tǒng)結(jié)構(gòu),終究有一天會(huì)土崩瓦解。重新去調(diào)整這個(gè)致命的缺點(diǎn),又跟重新改寫沒(méi)有兩樣,常常這樣讓人陷入進(jìn)退兩難的窘境。 如果我們可以用設(shè)計(jì)模式去思考解決問(wèn)題,如右圖將原系統(tǒng)視為一個(gè)子系統(tǒng),使用Facade這個(gè)樣式,重新產(chǎn)生使用接口,將這混亂的局面控制,不再像癌癥一樣繼續(xù)擴(kuò)散開來(lái),內(nèi)部的調(diào)整不再影響Client 的使用接口,那么就可以讓系統(tǒng)取得一個(gè)擴(kuò)充功能的契機(jī)。系統(tǒng)控充功能與內(nèi)部結(jié)構(gòu)的改善,這是兩個(gè)不同的方向,千萬(wàn)不要攪在一起,也不要同時(shí)去改變,這樣會(huì)使問(wèn)題更加的復(fù)雜,
俗語(yǔ)說(shuō):做衣容易,改衣難。這說(shuō)明一件事,雖然做衣服跟改衣服,用的是同樣的技術(shù),但卻是不同的思維,所以變成了會(huì)做衣服卻不一定會(huì)改衣服。對(duì)設(shè)計(jì)系統(tǒng)而言,系統(tǒng)中任何一個(gè)變動(dòng),就像改衣服一樣,學(xué)習(xí)克服這些變動(dòng),才能快速的反應(yīng)變動(dòng)。近年來(lái)軟件工程的思維傾向貼近客戶需求,擁抱改變,但這不光是口號(hào)而已,在這個(gè)思潮下,背后必須有強(qiáng)而有力的設(shè)計(jì)技術(shù)及思考模式所支撐,因此學(xué)習(xí)這些基本技術(shù)及不斷的磨練你的思考模式,才能去符合這樣的要求。本篇就是基于這樣的想法,將設(shè)計(jì)模式與重整兩個(gè)重要的基本技術(shù)加以結(jié)合運(yùn)用,實(shí)現(xiàn)系統(tǒng)面對(duì)改變時(shí),如何去反應(yīng)變動(dòng),及如何讓系統(tǒng)保持適當(dāng)?shù)膹椥浴?/p> 底下,對(duì)本篇所提供的實(shí)作范例,作簡(jiǎn)單扼要的說(shuō)明: 范例一
運(yùn)用Observer 觀察者模式解開單元之間的耦合
作者:陳國(guó)生 【解決問(wèn)題】 在Delphi 的對(duì)象中,TForm 是一個(gè)很搶眼的角色,因?yàn)樵谝粋€(gè)Form 當(dāng)中,我們可以輕易的結(jié)合許多不同的對(duì)象一起工作,幾乎是無(wú)所不能,但是在比較復(fù)雜的系統(tǒng)中,我們必須根據(jù)不同的功能,切割放在不同的Form 上面 ,或者說(shuō)是在不同單元當(dāng)中。當(dāng)一個(gè)系統(tǒng)存在許多不同單元之后,我們要如何去讓這些單元可以相互合作?使用USES 可以將兩個(gè)不同單元視為一個(gè)單元來(lái)使用,但遺憾的是,這種設(shè)計(jì)方式往往會(huì)造成單元之間的耦合性過(guò)高,當(dāng)一個(gè)單元變動(dòng)之后,往往其它的單元也會(huì)跟著受影響,而整個(gè)系統(tǒng)也就因此牽一發(fā)而動(dòng)全身了。
【運(yùn)用技術(shù)】 本范例將運(yùn)用Observer 觀察者樣式,來(lái)解決單元之間的糾纏不清。首先我們先來(lái)看看這個(gè)觀察樣式定義:觀察者模式定義對(duì)象間的一對(duì)多的相互關(guān)系,使得一個(gè)對(duì)象改變時(shí),其它相關(guān)對(duì)象皆可獲得通知并自動(dòng)更新。這個(gè)模式里面,會(huì)有一個(gè)觀察者,及一個(gè)以上的被觀察者,當(dāng)觀察者的狀態(tài)改變時(shí),被觀察者被主動(dòng)的告之,而觀察者負(fù)責(zé)通知,被觀察者卻不用知道觀察者是誰(shuí)。 從理解一個(gè)抽象概念的,到運(yùn)用在解決問(wèn)題上面,過(guò)程通常不是那么的容易。根據(jù)觀察的樣式提供的概念,其實(shí)Delphi 這個(gè)RAD 已經(jīng)幫我們?cè)O(shè)計(jì)許多功能強(qiáng)大的對(duì)象,所以重要的是,我們?nèi)绾稳ミ\(yùn)用這個(gè)概念去解決問(wèn)題,要把焦點(diǎn)放在解決問(wèn)題上面。 觀察者模式,有點(diǎn)類似Window里面的訊息傳遞機(jī)制,如果我們要實(shí)作這樣的機(jī)制,那么必須要有一個(gè)可以儲(chǔ)存這些訊息及事件的容器型對(duì)象。在Delphi 中有許多現(xiàn)成的對(duì)象,你無(wú)須費(fèi)心的去設(shè)計(jì)這樣的對(duì)象,只要找出可以實(shí)踐這樣想法的對(duì)象即可,本范例中,我們運(yùn)用TActionList來(lái)實(shí)現(xiàn),TActionList 是一個(gè)事件串行,現(xiàn)在就看我們?nèi)绾紊朴眠@個(gè)對(duì)象,去達(dá)到訊息傳遞的目的了。 在下面的范例中,我們將實(shí)作一個(gè)橫跨整個(gè)系統(tǒng)的觀察者樣式,解開單元之間的耦合問(wèn)題。 【實(shí)作范例】 第五步,在Form2的Edit1的OnKeyPress 寫入: 從這個(gè)范例中,可以將Form2視為是一個(gè)觀察者,而Form1 是一個(gè)被觀察者,當(dāng)Form2的TEdit的值改變后,透過(guò)事件通知,改變了Form1的TEdit,然而Form2 并無(wú)USES Form1 ,也不知道Form1的存在,所以即使Form1消失了,仍然不會(huì)影響Form2的運(yùn)作。 【結(jié) 論】 在一個(gè)大的系統(tǒng)里面,控制單元之間的耦合性非常重要,以上述的范例來(lái)說(shuō),不論系統(tǒng)如何改變,各個(gè)單元都可以維持正常的運(yùn)作,既相互合作又不會(huì)相互影響,其變動(dòng)姓被有效的控制在一個(gè)事件串行當(dāng)中,當(dāng)單元變動(dòng)時(shí),我們很容易追蹤,且不會(huì)擴(kuò)散到整個(gè)系統(tǒng)。
運(yùn)用Template Method 樣式設(shè)計(jì)數(shù)據(jù)庫(kù)的異動(dòng)交易控制
作者:陳國(guó)生
【解決問(wèn)題】 什么是異動(dòng)交易控制?簡(jiǎn)單的說(shuō),就是如何確保在資料改變的過(guò)程,可以順利的完成,異動(dòng)交易控制最主要的著眼點(diǎn)在于對(duì)交易失敗的控制,試想一個(gè)交易,基于某種不可預(yù)期的原因造成程序產(chǎn)生錯(cuò)誤,中途被迫終止交易,那之前已經(jīng)改變的資料算不算數(shù)?如果不算數(shù),那之前已經(jīng)交易的資料怎么辦呢? 舉例來(lái)說(shuō),一張進(jìn)貨單可能要同時(shí)更新單據(jù)檔及庫(kù)存檔,如果中途失敗,可能造成單據(jù)文件有資料而庫(kù)存文件沒(méi)有更新,要如何才能避免這種嚴(yán)重的錯(cuò)誤呢?那就是必須進(jìn)行異動(dòng)交易的控制,在一個(gè)異動(dòng)交易控制中,只要有一筆交易失敗,那么之前所有交易的資料,將被還原至交易之前。 在Delphi 的Connection 對(duì)象已經(jīng)提供了良好的控制程序。以TAdoConnection為例,它的語(yǔ)法格式如下: try
【面臨的問(wèn)題】 雖然Delphi 已經(jīng)有了很好的解決方式,但是對(duì)一些已經(jīng)寫好的交易程序,我們?cè)诓蛔儎?dòng)原有的程序代碼,如何進(jìn)行功能的擴(kuò)充呢?
【使用技術(shù)】 這個(gè)案例,我們將利用到重整技術(shù)的概念及樣式設(shè)計(jì)來(lái)解決這個(gè)問(wèn)題。范例中我們會(huì)用到Template Method 這個(gè)樣式來(lái)設(shè)計(jì)一個(gè)程序,什么叫Template Method ?它的定義如下: 在父類別中定義一個(gè)算法的骨架,但將一些步驟延遲到其子類別中執(zhí)行。套句話說(shuō),一個(gè)人犯罪是要坐牢的,這個(gè)犯罪要坐牢就是一個(gè)樣版,至于做幾年的牢,要看當(dāng)時(shí)犯了什么罪才來(lái)決定。 這樣的說(shuō)法還是很抽象,我們進(jìn)一步說(shuō)明這個(gè)抽象的概念的運(yùn)用時(shí)機(jī): 利用Template Method 可以定義一些共享的算法,差異性部分則由子類別去實(shí)作,讓一些有差異性的子類別,擁有共同的算法,如此則程序不但有彈性,且易于維護(hù)。 我們應(yīng)該可以想象,異動(dòng)交易控制就是一個(gè)算法,這個(gè)算法會(huì)被利用在許多需要控制異動(dòng)交易的地方,每個(gè)異動(dòng)交易的內(nèi)容是不一樣的,但異動(dòng)控制的運(yùn)算卻是一致的。Template Method 這個(gè)樣式的重點(diǎn)乃在區(qū)分變與不變的地方,將不變的部分寫成骨架,將變的部分保留起來(lái),對(duì)于一個(gè)異動(dòng)交易控制程序來(lái)說(shuō),異動(dòng)交易內(nèi)容是變動(dòng)的部分,而異動(dòng)控的運(yùn)算是不變的部分。 【實(shí)作范例】 接下來(lái),我們來(lái)看一下,如何運(yùn)用這個(gè)樣式來(lái)解決問(wèn)提呢,假設(shè)你有一個(gè)異動(dòng)程序是這樣: // 異動(dòng)程序 現(xiàn)在,我們要為這個(gè)異動(dòng)程序增加異動(dòng)控能力,只要增加這樣的一個(gè)程序就可以了: procedure TForm1.Button1Click(Sender: TObject);
這個(gè)范例運(yùn)用Template Method 樣式,避免修改已經(jīng)完成的程序,同時(shí)又可以增加系統(tǒng)的功能。當(dāng)然這個(gè)范例,也可以運(yùn)用類別繼承的方式來(lái)實(shí)現(xiàn),其寫作的方式,與上述的范例,亦相去無(wú)幾,原事件改成宣告一個(gè)虛擬的程序,并在子類別中去實(shí)作這個(gè)程序即可,運(yùn)用的概念是一樣的,這正是所謂戲法人人會(huì)變,巧妙各有不同,融會(huì)貫通之后就可以運(yùn)用自如了。
范例三
運(yùn)用Factory 工廠模式設(shè)計(jì)多人使用的權(quán)限控制
作者:陳國(guó)生 在一個(gè)多人使用的系統(tǒng)中,根據(jù)不同的使用者,必須設(shè)計(jì)出不同的使用權(quán)限,要設(shè)計(jì)這樣的權(quán)限控管機(jī)制,很顯然相當(dāng)復(fù)雜而且繁瑣。因此,如何使用一個(gè)簡(jiǎn)單又容易維護(hù)的方式進(jìn)行系統(tǒng)設(shè)計(jì)?在軟件設(shè)計(jì)領(lǐng)域里面,簡(jiǎn)單就是美,這是在靈活塑模里面的一個(gè)宣言,追求簡(jiǎn)單,其實(shí)不簡(jiǎn)單,同樣的一個(gè)問(wèn)題,有千百種解法,如何使用一個(gè)簡(jiǎn)單又有彈性的設(shè)計(jì),是程序設(shè)計(jì)者追求的極致,本范例的重點(diǎn)就是要具體實(shí)踐這個(gè)目標(biāo)。
【面臨問(wèn)題】 對(duì)已經(jīng)寫好的程序,我們不希望修改,因此如何以擴(kuò)充功能的方法,將此權(quán)限控制的功能加入系統(tǒng)?
在重整技術(shù)中,有一個(gè)重要的原則,就是不要去更動(dòng)已經(jīng)設(shè)計(jì)好的程序,因此我們將設(shè)計(jì)一個(gè)即插即用的單元,為系統(tǒng)擴(kuò)充多人使用的控管機(jī)制,因此在這個(gè)構(gòu)想下,我們運(yùn)用Factory 工廠模式的設(shè)計(jì)樣式來(lái)實(shí)現(xiàn)這個(gè)設(shè)計(jì)。 現(xiàn)在,我們假設(shè)每一個(gè)使用者登入時(shí),會(huì)對(duì)應(yīng)到一個(gè)權(quán)限對(duì)象,然后針對(duì)這個(gè)對(duì)象去設(shè)計(jì)使用權(quán)限即可。換句話說(shuō),也就是說(shuō)讓不同的使用者對(duì)應(yīng)到不同的對(duì)象上面,再運(yùn)用工廠模式,根據(jù)不同的使用者,自動(dòng)產(chǎn)生不同的對(duì)象,如此便可達(dá)到權(quán)限控制的目的。 當(dāng)然,控制使用的權(quán)限,依控管方式不同,會(huì)方法有很多種,下面范例將提供其中一種控管方法。
【范例實(shí)作】 至此,我們已經(jīng)把準(zhǔn)備對(duì)應(yīng)到使用者的權(quán)限對(duì)象TMainMenu 都設(shè)計(jì)完成了,接下來(lái)只要根據(jù)不同的使用者輸出不同對(duì)象即可,這部分要如何設(shè)計(jì)呢?首先我在TDataNodule 的OnCreate事件中,加入判斷使用者的功能,并輸出對(duì)象: procedure TDataModule1.DataModuleCreate(Sender: TObject); var // 接下來(lái)輸出對(duì)象至主畫面 以上完成之后,最后的一個(gè)步驟是把TDataModule 在項(xiàng)目中自動(dòng)建構(gòu)起來(lái),由于設(shè)計(jì)上是自動(dòng)輸出對(duì)象至MainForm,所以TDataModule 的建構(gòu)必須在MainForm 之后,這樣就算大功告成了。注意:本范例無(wú)處理User 登錄的功能,系使用傳遞參數(shù)的方法來(lái)判斷使用者,這部分請(qǐng)自行參考變化。
【結(jié) 論】 工廠模式的對(duì)象產(chǎn)生方式,可以動(dòng)態(tài)產(chǎn)生,也可以靜態(tài)建立,Delphi 中有兩個(gè)對(duì)象可以很方便的存放這些事先建好的對(duì)象,一個(gè)是TForm ,一個(gè)TDataModule,在本范例中,是利用TDatamodule 存放事先建立好的對(duì)象,讓Client 端可以很方便的取得這些對(duì)象。
|
|
|