尚 偉,劉志廣,張 沫
(1.中國電子科技集團(tuán)公司第五十四研究所,河北石家莊050081;2.河北文化信息資源共享中心,河北石家莊050011)
耦合度是標(biāo)識軟件系統(tǒng)好壞的一個(gè)重要屬性,軟件系統(tǒng)中存在過多的耦合會使系統(tǒng)變得復(fù)雜,錯(cuò)誤率增加,從而使系統(tǒng)難于更改和維護(hù)。過度的耦合不利于模塊的設(shè)計(jì)和重用,為了提高模塊化和封裝性,應(yīng)該盡量減少對象類之間的耦合。在系統(tǒng)設(shè)計(jì)過程中,特別是系統(tǒng)框架的設(shè)計(jì)過程中,降低軟件系統(tǒng)的耦合性是改善軟件系統(tǒng)的可維護(hù)性、可理解性和可擴(kuò)展性的關(guān)鍵。采用合理的設(shè)計(jì)模式為目前改善軟件系統(tǒng)耦合性的常用方法。
設(shè)計(jì)模式是按照建筑設(shè)計(jì)領(lǐng)域模式思想對軟件設(shè)計(jì)領(lǐng)域的總結(jié)和歸納,對軟件行業(yè)的發(fā)展有重要推動的作用。計(jì)算機(jī)科學(xué)中對設(shè)計(jì)模式的簡單定義就是對于一類重復(fù)出現(xiàn)的問題的一種可重用的解決方案,在軟件工程中一個(gè)設(shè)計(jì)模式對應(yīng)解決一類軟件設(shè)計(jì)問題。設(shè)計(jì)模式是成功的軟件架構(gòu)設(shè)計(jì)經(jīng)驗(yàn)總結(jié),是被實(shí)踐證明的可復(fù)用的解決方案。設(shè)計(jì)模式解決了軟件開發(fā)中有關(guān)對象的創(chuàng)建、結(jié)構(gòu)和行為等一系列問題。如果多個(gè)項(xiàng)目有相同的問題背景,那么可以應(yīng)用相同的設(shè)計(jì)模式加以解決。在軟件設(shè)計(jì)中使用設(shè)計(jì)模式可以減少各個(gè)類之間的依賴和藕合,增強(qiáng)結(jié)構(gòu)復(fù)用性,減少因變更所做的設(shè)計(jì)調(diào)整。觀察者設(shè)計(jì)模式就是這樣的一種低耦合設(shè)計(jì)技術(shù)。
觀察者模式是一種行為性設(shè)計(jì)模式。它定義了一個(gè)對象間一對多的信賴關(guān)系,當(dāng)一個(gè)對象改變狀態(tài)時(shí),所有與它有信賴關(guān)系的對象都得到通知并自動更新。適用于以下的情況:①一個(gè)抽象的模型擁有2個(gè)方面,其中一個(gè)方面依賴于另一個(gè)方面。將這2個(gè)方面封裝在獨(dú)立的對象中,可以使它們各自獨(dú)立地改變和復(fù)用;②一個(gè)對象改變時(shí),也要改變其他對象,但不知道具體有多少對象需要改變;③一個(gè)對象必須通知其他對象自己狀態(tài)的改變,而又不能假定其他對象是誰。使用觀察者模式,可以減少目標(biāo)和觀察者對象間的耦合程度,并且這種模式支持廣播通信,可以同時(shí)改變多個(gè)對象的狀態(tài)。
觀察者模式定義了目標(biāo)對象和觀察者對象之間的一種一對多的依賴關(guān)系,當(dāng)目標(biāo)對象的狀態(tài)發(fā)生了改變,它要能夠把這一信息通知給所有依賴于它的觀察者對象,而各個(gè)觀察者對象根據(jù)通知信息來恰當(dāng)?shù)貙ψ约旱谋憩F(xiàn)形式進(jìn)行更新。觀察者模式結(jié)構(gòu)如圖1所示。
圖1 觀察者模式結(jié)構(gòu)
圖1中目標(biāo)類提供注冊和刪除觀察者對象的接口;而觀察者類為那些在目標(biāo)發(fā)生改變時(shí)需獲得通知的對象定義一個(gè)更新接口;當(dāng)具體目標(biāo)類的狀態(tài)發(fā)生變化時(shí),負(fù)責(zé)向它的各個(gè)觀察者發(fā)送通知;具體觀察者類存儲有關(guān)狀態(tài),實(shí)現(xiàn)觀察者的更新接口以使自身狀態(tài)與目標(biāo)狀態(tài)一致。
如果2個(gè)類的訪問或通信是直接通過彼此調(diào)用實(shí)現(xiàn)的,這樣2個(gè)類間的耦合關(guān)系就會非常緊密。根據(jù)圖1中的結(jié)構(gòu)可以看出,觀察者模式中目標(biāo)類與具體觀察者類是通過觀察者這個(gè)接口的方式實(shí)現(xiàn)彼此間通訊的,而具體觀察者類是負(fù)責(zé)具體實(shí)現(xiàn)該接口以及函數(shù)的類,這種結(jié)構(gòu)實(shí)現(xiàn)了接口與實(shí)現(xiàn)分離的策略。這樣的設(shè)計(jì)也使得具體目標(biāo)與具體觀察者不直接關(guān)聯(lián),具體目標(biāo)變化時(shí)通知觀察者,只需通過注冊的觀察者接口完成更新操作(更新的具體實(shí)現(xiàn)在具體觀察者類中),即具體目標(biāo)類不需要知道具體觀察者類,這樣做降低了目標(biāo)類與具體觀察者類的耦合度。
觀察者模式中目標(biāo)與觀察者是一對多的關(guān)系,在實(shí)際的程序設(shè)計(jì)中目標(biāo)對象使用一個(gè)數(shù)組或鏈表成員變量來維護(hù)它的多個(gè)觀察者對象。注冊函數(shù)和刪除函數(shù)是添加或刪除觀察者對象的接口。通知函數(shù)是當(dāng)目標(biāo)對象狀態(tài)改變時(shí)通知它的所有觀察者對象的接口。在目標(biāo)對象的通知函數(shù)接口中常用數(shù)組或鏈表保存依賴于主題對象的觀察者對象,同時(shí)在該接口中將對這些對象進(jìn)行遍歷,每遍歷到一個(gè)觀察者對象時(shí)就會調(diào)用它的更新函數(shù)接口。更新函數(shù)根據(jù)消息的類型使得觀察者對象對目標(biāo)對象的狀態(tài)變化做出相應(yīng)的更新。這樣,目標(biāo)對象的一個(gè)通知函數(shù)執(zhí)行下來,它的所有觀察者對象都更新了。
對具體目標(biāo)類來說,它從基類(目標(biāo)類)派生,在基類的基礎(chǔ)上增加了自身的狀態(tài)數(shù)據(jù)。當(dāng)自身的狀態(tài)數(shù)據(jù)發(fā)生變化時(shí)根據(jù)需要向觀察者對象發(fā)送消息。具體的觀察者對象存儲自身狀態(tài),但往往這些狀態(tài)是由觀察者的目標(biāo)類內(nèi)容決定的。在邏輯上它們必須保持一致,觀察者在實(shí)際的設(shè)計(jì)中往往設(shè)計(jì)成一個(gè)虛基類,更新函數(shù)是一個(gè)純虛函數(shù),這樣才可以利用面向?qū)ο蟮亩鄳B(tài)性調(diào)用各個(gè)觀察者接口的實(shí)現(xiàn)類的更新函數(shù)。所以具體的觀察者類的一個(gè)重要任務(wù)就是實(shí)現(xiàn)接口(觀察者的更新函數(shù)),所有具體觀察者類的狀態(tài)維護(hù)都靠它來完成。
報(bào)警處理系統(tǒng)是管理和接收報(bào)警信息,根據(jù)報(bào)警事件制定和管理預(yù)案,完成報(bào)警事件處置的信息系統(tǒng),其主要功能是報(bào)警信息處置管理、報(bào)警事件檢索分析、管理和收發(fā)格式化信息、文書信息管理、預(yù)案管理、勤務(wù)通信和短信管理等。
系統(tǒng)的用戶需求可分為不變部分和易變部分。需求的不變部分:①信息的收發(fā)基本功能不變;②收發(fā)文的模板及其相應(yīng)數(shù)據(jù)的表現(xiàn)形式穩(wěn)定:這些模板都是長期實(shí)踐保存下來的,被相應(yīng)部門廣泛使用的固定格式,一般不會輕易改變;③信息發(fā)送的操作方式相對穩(wěn)定:都是選擇固定的地址,再根據(jù)相應(yīng)模板進(jìn)行內(nèi)容調(diào)整后進(jìn)行發(fā)送。需求的易變部分有:用戶界面易變,報(bào)警處理軟件的開發(fā)者畢竟不是軟件的使用者,那么軟件開發(fā)者就必須去適應(yīng)軟件使用者對軟件界面多變的要求,如何在滿足使用者要求的同時(shí)最大程度地減少軟件改寫的開銷成為必須解決的問題。
報(bào)警處理系統(tǒng)的主體功能是報(bào)警事件的接收顯示及處置。系統(tǒng)對于接收到的報(bào)警信息根據(jù)其地理坐標(biāo)及相應(yīng)屬性顯示在地圖背景上,并利用聲、光等輔助手段提示用戶。用戶發(fā)現(xiàn)報(bào)警后利用系統(tǒng)提供的界面可對報(bào)警事件進(jìn)行處置(關(guān)聯(lián)預(yù)案、通知相應(yīng)部門、啟動報(bào)警記錄等),處置后的報(bào)警信息將在用戶界面進(jìn)行更新,取消閃爍并停止聲、光提示。
系統(tǒng)中界面顯示和業(yè)務(wù)處理功能相分離,外層界面依賴于業(yè)務(wù)功能模塊,它們各自又可獨(dú)立地改變和復(fù)用;此外,兩部分中當(dāng)一方改變時(shí),也要通知并改變另一方,所以使用MVC(模型—視圖—控制器)架構(gòu)作為整體結(jié)構(gòu)設(shè)計(jì)決策。系統(tǒng)中的視圖部分用于顯示模型狀態(tài)、接收數(shù)據(jù)更新請求和發(fā)送用戶請求給控制器。在工程中實(shí)例化為地圖顯示相關(guān)的類,它們完成報(bào)警信息的圖上顯示、啟動閃爍、更新狀態(tài)和停止閃爍燈操作。模型部分用于封裝應(yīng)用程序狀態(tài)、響應(yīng)狀態(tài)查詢、處理業(yè)務(wù)流程和通知業(yè)務(wù)狀態(tài)更新。在工程中實(shí)例化為報(bào)警信息管理的相關(guān)數(shù)據(jù)類,它完成報(bào)警數(shù)據(jù)的庫檢索和報(bào)警數(shù)據(jù)的結(jié)構(gòu)化等工作??刂破鞑糠钟糜诮邮沼脩粽埱?、調(diào)用模型響應(yīng)用戶請求和選擇視圖顯示響應(yīng)結(jié)果。工程中實(shí)例化為報(bào)警信息管理的諸多界面類,完成圖上顯示的控制以及報(bào)警信息的管理等操作。主體功能架構(gòu)圖如圖2所示。
圖2 主體功能架構(gòu)
每個(gè)系統(tǒng)都有自己的特點(diǎn),不能照抄照搬別人的設(shè)計(jì)模式,應(yīng)該找到符合自己的系統(tǒng)設(shè)計(jì),走出一條適合自己的開發(fā)之路。為了實(shí)現(xiàn)上述系統(tǒng),并盡可能切斷系統(tǒng)各模塊之間的耦合,提高系統(tǒng)的擴(kuò)展性,引入了觀察者模式。系統(tǒng)的開發(fā)利用VC6.0工具,根據(jù)實(shí)際的情況設(shè)計(jì)中沒有對觀察者模式中目標(biāo)類做繼承關(guān)系的設(shè)計(jì)(應(yīng)用中的Subject比較簡單,沒有復(fù)雜的層次關(guān)系,不需要專門抽象一層來)。下面對系統(tǒng)中的主要類的關(guān)系和結(jié)構(gòu)進(jìn)行說明。
系統(tǒng)中的類可以分為界面類、數(shù)據(jù)類和觀察者類3種。對于每個(gè)功能模塊來說,由于使用觀察者接口,界面類的變化(比如使用控件的變化)不需要更改數(shù)據(jù)類,而數(shù)據(jù)類的變化(比如增加了一些新操作)也不需要更改相應(yīng)的界面類。對象設(shè)計(jì)結(jié)構(gòu)如圖3所示。
圖3 系統(tǒng)設(shè)計(jì)結(jié)構(gòu)
系統(tǒng)設(shè)計(jì)結(jié)構(gòu)圖中,主控類聚合了文書管理、預(yù)案管理、報(bào)警管理和收發(fā)文管理4個(gè)窗口類。對于這4個(gè)功能模塊來說設(shè)計(jì)結(jié)構(gòu)相同,這里就不再重復(fù)敘述,僅對報(bào)警管理功能模塊進(jìn)行詳細(xì)介紹。
報(bào)警信息管理數(shù)據(jù)類調(diào)用報(bào)警處置信息變動觀察者類中的報(bào)警處置管理虛函數(shù),間接調(diào)用報(bào)警信息管理界面類中報(bào)警處置相關(guān)的實(shí)現(xiàn)函數(shù),報(bào)警信息管理界面類繼承報(bào)警處置信息變動觀察者類,是具體實(shí)現(xiàn)報(bào)警處置信息變動觀察者類中虛函數(shù)操作的類,它利用接口(報(bào)警處置信息變動觀察者類中的虛函數(shù))調(diào)用報(bào)警信息管理界面類中的實(shí)現(xiàn)函數(shù)即可以實(shí)現(xiàn)報(bào)警目標(biāo)的圖上顯示、報(bào)警處置和報(bào)警關(guān)閉對應(yīng)界面的更新。
其中,報(bào)警處置信息變動觀察者類在觀察者模式中對應(yīng)觀察者類,它為其所觀察的目標(biāo)類的改變定義了更新的接口;報(bào)警信息管理界面類承擔(dān)的是觀察者模式中具體觀察者類的職責(zé),它是報(bào)警處置信息變動觀察者類的子類,繼承了父類的接口并實(shí)現(xiàn)了這個(gè)更新接口,此外它還存儲報(bào)警的狀態(tài),利用更新接口使得自身狀態(tài)與其觀察的目標(biāo)對象狀態(tài)保持一致。報(bào)警信息管理數(shù)據(jù)類充當(dāng)?shù)氖怯^察者模式中具體目標(biāo)類和目標(biāo)類二者的角色,它不僅提供對于觀察者的注冊和刪除功能,還提供對注冊的觀察者狀態(tài)進(jìn)行獲取、設(shè)置的功能,當(dāng)報(bào)警狀態(tài)因報(bào)警處置(結(jié)束報(bào)警)或接收報(bào)警(啟動報(bào)警)而改變時(shí),該類可獲得狀態(tài)并將狀態(tài)的更改通知與之相關(guān)的觀察者,完成報(bào)警信息管理界面類上的報(bào)警狀態(tài)閃爍與否的更新。
雖然采用觀察者模式具有諸如松耦合、易于復(fù)用和變更較少等優(yōu)勢,但該模式的使用需要注意如下問題:
①松偶合導(dǎo)致代碼關(guān)系不明顯,尤其是模式代碼混入到參與類中來,而產(chǎn)生嚴(yán)重的代碼分散問題,降低代碼的可讀性。不過,如果代碼閱讀者熟知觀察者模式則代碼理解上會更容易一些;
②如果一個(gè)Subject被大量Observer訂閱的話,在廣播通知的時(shí)候可能會有效率問題。畢竟通知只是簡單的遍歷,所以當(dāng)存在大量觀察者時(shí),這種問題會凸顯出來。這個(gè)時(shí)候往往意味著設(shè)計(jì)上可能存在缺陷,需要考慮修改設(shè)計(jì),增加多個(gè)觀察者接口;
③雖然觀察者模式可以隨時(shí)使觀察者知道所觀察的對象發(fā)生了變化,但是觀察者模式?jīng)]有相應(yīng)的機(jī)制使觀察者知道所觀察的對象是怎么發(fā)生變化的。如果需要獲得這種變化,則需要針對變化做出相應(yīng)的處理,比如在觀察者刷新函數(shù)(Update)中增加變化因素作為參數(shù)。
實(shí)踐證明,觀察者設(shè)計(jì)模式這種設(shè)計(jì)技術(shù)的采用提高了軟件開發(fā)的效率,提高了系統(tǒng)的可重用性和可擴(kuò)展性,降低了軟件系統(tǒng)中模塊間的耦合度。誠然,設(shè)計(jì)模式并不是萬能的,但它提供了一種在開發(fā)人員和組織之間共享可使用解決方案的方法,這些解決方案是凝聚了很多設(shè)計(jì)者積累的知識和經(jīng)驗(yàn)的最佳實(shí)踐。采用適合自己的設(shè)計(jì)模式將能夠敏捷地構(gòu)建信息系統(tǒng),更好更快地實(shí)現(xiàn)用戶需求。
[1]ERICH G,RICHARD H,RALPH J,et al.Design Patterns:Elements of Reusable Object-Oriented Software[M].李英軍,馬曉星,蔡 敏,等譯.北京:機(jī)械工業(yè)出版社,2007.
[2]吳善明,沈建京,劉 輝.淺析Observer模式在GIS軟件設(shè)計(jì)中的應(yīng)用[J].計(jì)算機(jī)工程與設(shè)計(jì),2007,28(18):4532-4534.
[3]付登科,郝克剛,葛 瑋.AOP改進(jìn)觀察者模式——實(shí)現(xiàn)關(guān)注點(diǎn)的分離[J].計(jì)算機(jī)應(yīng)用(自然科學(xué)版),2005,25(S1):410-412.
[4]肖計(jì)劃,劉海硯,張吉才.設(shè)計(jì)模式在地圖制圖軟件開發(fā)中的應(yīng)用[J].測繪工程,2008,17(5):4-7.
[5]王 宇,王 力,李增智,等.面向?qū)ο筌浖蚣苤械鸟詈闲约捌湎獠呗缘难芯縖J].小型微型計(jì)算機(jī)系統(tǒng),2003,24(10):1743-1746.
[6]李 進(jìn),師建東,周 琦.一種基于模式的應(yīng)用網(wǎng)關(guān)設(shè)計(jì)[J].無線電工程,2009,39(9):1-2.