杜 瑩,龔桂榮,陳 剛
(信息工程大學 測繪學院,河南 鄭州 450052)
三維地形環(huán)境仿真系統(tǒng)經(jīng)過多年的發(fā)展,已經(jīng)從僅支持簡單的局部地形瀏覽,演進到支持面向全球的多源異構(gòu)、多時相數(shù)據(jù),甚至可以作為一種基礎(chǔ)平臺,在其上搭建以空間和時間為基準的各種仿真應(yīng)用系統(tǒng)。但是,如果基礎(chǔ)平臺的架構(gòu)設(shè)計不合理,各模塊間耦合度高,就極有可能給軟件開發(fā)帶來諸多不便甚至危害。因此,需要在平臺設(shè)計過程中充分考慮此類問題,這樣才能得到一個高效、高質(zhì)的仿真平臺。而解決上述問題的一個有效辦法,就是設(shè)計模式。
設(shè)計模式是軟件復用技術(shù)中的一個重要概念。它為開發(fā)者提供了一種考慮問題、解決問題的方式,其目的是將軟件開發(fā)中成功的經(jīng)驗予以總結(jié)并推廣,以求在相同的問題領(lǐng)域中,能夠使其他設(shè)計人員從中得到啟發(fā)和幫助[1]。
隨著技術(shù)的不斷完善,設(shè)計模式的種類日益增多,相對于Gang of Four(GOF)1995年提出的23種通用的設(shè)計模式,數(shù)量已經(jīng)大大增加了。要從如此多的模式中選擇適合自己系統(tǒng)的模式并非易事,選擇正確、恰當?shù)哪J匠蔀樵O(shè)計模式的使用瓶頸[2]。因此,必須先認真分析系統(tǒng)本身的特點和需求,總結(jié)需要解決的問題,有的放矢地尋找若干簡單有效的設(shè)計模式,避免出現(xiàn)“反模式”和“錯誤模式”。
基于松耦合的設(shè)計原則,本文為三維地形環(huán)境仿真平臺設(shè)計了組件化的體系架構(gòu)(見圖1),其基本思想是“分治法”,即將系統(tǒng)分解成可獨立開發(fā)的松耦合組件,使其在可靠性、重用性和可擴展性等非功能性問題上有良好表現(xiàn)[5]。
圖1 三維地形環(huán)境仿真平臺的體系架構(gòu)
其中,主控層負責內(nèi)部的各種交互與控制,疏通仿真平臺與各功能組件的通道,同時松散各組件之間的耦合度;功能組件層以接口形式為平臺提供各種功能,其相互間的交互通過主控層完成;數(shù)據(jù)訪問組件作為一個特殊的組件,負責完成地形數(shù)據(jù)的調(diào)度與存取。
這種層次化、組件化的體系架構(gòu)清晰明了,非常便于分工合作。但要真正把這種體系架構(gòu)落實到應(yīng)用,還有幾個關(guān)鍵環(huán)節(jié)需要設(shè)計好,這也是本文著重要解決的幾個問題。
問題1:主控與各個功能組件之間如何進行通信。主控與各個功能組件之間是一對多的關(guān)系,所有的消息、命令和交互等都要通過主控分發(fā)到相關(guān)組件,并由組件做出響應(yīng)??紤]到三維地形環(huán)境仿真系統(tǒng)實時性、交互性強等特點,這種分發(fā)和響應(yīng)工作會非常頻繁,處理不好就會制約后續(xù)事件分發(fā)和響應(yīng)的進程。
問題2:各個功能組件如何通過地形訪問組件獲取數(shù)據(jù)。在圖1所示的體系架構(gòu)中,很多組件都需要與地形數(shù)據(jù)發(fā)生交互,如三維地形組件需要調(diào)度地形數(shù)據(jù)進行繪制,三維分析組件需要獲取高程數(shù)據(jù)進行坡度、通視等分析,三維相機組件需要獲取當前視場范圍內(nèi)的最大高程值,以便進行碰撞檢測,等等。如果這些組件都直接去訪問地形數(shù)據(jù)庫或數(shù)據(jù)文件,不僅會造成大量的代碼冗余,一旦數(shù)據(jù)格式發(fā)生改變,還會引發(fā)多個組件的多處改動。這就是圖1中地形訪問組件的設(shè)計初衷,即通過統(tǒng)一的渠道訪問地形數(shù)據(jù)。
問題3:如何應(yīng)對多源異構(gòu)的地形數(shù)據(jù)。隨著數(shù)據(jù)獲取手段的豐富,地形數(shù)據(jù)尤其是地形紋理數(shù)據(jù)趨于多樣化,可能來源不同,如來源于不同的傳感器、不同的拍攝日期、不同的分辨率等;也可能存儲方式不同,如存儲于本地文件、本地數(shù)據(jù)庫、遠程服務(wù)器等。諸多不同導致地形訪問組件面臨巨大的考驗,如何才能做到“以不變應(yīng)萬變”,不隨數(shù)據(jù)源的改變而顛覆以往的設(shè)計和接口。
上述3個問題雖然側(cè)重點不同,但它們有著一個共同特點,即都屬于非功能性問題,都涉及到軟件的靈活性和可擴展性。顯然,設(shè)計模式是解決該類問題的不二選擇。
然而,設(shè)計模式的描述主要是以自然語言結(jié)合OO框圖的描述方法,一些語言描述有一定的歧義性,使設(shè)計者在為特定問題選擇設(shè)計模式時往往會猶豫不決。雖然設(shè)計模式有許多優(yōu)點,但是仍然需要人們掌握它的本質(zhì)并學會正確的使用方法,才能夠正確應(yīng)用并真正發(fā)揮它的優(yōu)勢,同時應(yīng)該避免濫用帶來的軟件結(jié)構(gòu)的復雜性和冗余,不能為了使用模式而使用[2]。
鑒于設(shè)計模式的復雜性,作者對第2節(jié)中提出的3個問題進行了抽象,并按照設(shè)計模式的分類方式進行了歸類和匹配,從而提出分別用職責鏈模式、代理模式和橋接模式解決這3個問題。
三維地形環(huán)境仿真系統(tǒng)具有實時性、交互性強等顯著特點,如用戶在場景中的鼠標操作需要由主控分發(fā)到多個組件,場景的相機位置發(fā)生改變需要通知到多個組件,等等。如何處理好主控與各個功能組件之間這種復雜的請求與反饋關(guān)系呢?作者經(jīng)過分析,選擇了“職責鏈模式”來解決這個問題。
職責鏈模式(Chain of Responsibility Pattern),是指使多個對象都有機會處理請求,同時避免請求的發(fā)送者和接收者之間的耦合關(guān)系。將這些對象連成一條鏈,并沿著這條鏈傳遞該請求,直到有一個對象處理它為止[3]。這種模式應(yīng)用很廣,它的最大優(yōu)勢是接收者和發(fā)送者都不需要對方的明確信息,即可完成請求的發(fā)送和處理。如圖2所示,為職責鏈模式的UML圖。
然而,圖2只是職責鏈的標準模式,它雖然具有很好的擴展性,可以使軟件具有動態(tài)增加請求處理者的能力,但卻存在著兩個很現(xiàn)實的問題:
圖2 職責鏈模式的UML圖
1)每次請求最多只有一個Handler能接受處理,其它Handler都是無用實例,如果一個請求到鏈的末端都得不到處理,或者因為沒有正確配置而得不到處理,就會導致所有Handler都成無用實例。
2)在某些特殊情況下,可能有多個Handler需要接受處理,也有可能某些Handler允許或不允許其后繼者繼續(xù)處理請求(如在響應(yīng)鍵盤事件時,某些組件試圖鎖定某些熱鍵,不允許其后繼組件使用,但并非鎖定所有按鍵),圖2中的標準模式是無法解決這個問題的。
針對這兩個問題,作者對圖2中職責鏈的標準模式進行了改進,如圖3所示。
圖3 改進后職責鏈模式的UML圖
圖3主要做了如下兩點改進:
1)針對問題1,使用發(fā)布-訂購(Publish/Subscribe)模式,只讓對相關(guān)請求“感興趣”的組件并實例化,這些組件需要預先訂購這些請求,本文將其由“Handler”更名為“Subscriber”(訂購者)。這樣,在發(fā)送請求時,3D主控只需要面向訂購了該請求的組件,也就不會出現(xiàn)無用的Handler了。
2)針對問題2,為Subscriber的接口函數(shù)HandleRequest()增加一個bool型參數(shù)lock,表示當前處理者是否允許其后繼者繼續(xù)處理該請求,如果lock為true,表示當前組件鎖定該請求,職責鏈不再向下傳遞請求;否則,請求繼續(xù)傳遞,直到lock再次為true或職責鏈走到末端。這樣就解決了多個Handler需要處理請求或鎖定請求的問題。
在三維地形環(huán)境基礎(chǔ)平臺中,很多組件都需要與地形數(shù)據(jù)發(fā)生交互,如果這些組件都直接去訪問地形數(shù)據(jù)庫或數(shù)據(jù)文件,不僅會造成大量的代碼冗余,一旦數(shù)據(jù)格式發(fā)生改變,還會引發(fā)多個組件的多處改動。如何確保各個組件能通過統(tǒng)一的渠道訪問到地形數(shù)據(jù)呢?作者經(jīng)過分析,選擇了“代理模式”來解決這個問題。
代理模式(Proxy Pattern),是指為其它對象提供一種代理,以控制對這個對象的訪問[3]。如圖4所示,為代理模式的UML圖。
圖4 代理模式的UML圖
DBProxy接口:定義了DB(數(shù)據(jù)庫)和DBProxy(數(shù)據(jù)庫代理)的共用接口,這樣在任何需要使用地形數(shù)據(jù)(即需要調(diào)用DB)的地方都可以使用DBProxy,所有需要與地形數(shù)據(jù)交互的組件只需要通過統(tǒng)一的DBProxy接口即可,而無需了解DB本身的格式或格式是否發(fā)生了變化;
DB類:定義DBProxy類所代表的真實實體;
DBProxy類:保存一個引用使得代理可以訪問實體,并提供一個與DBProxy的接口相同的接口,這樣代理就可以用來代替實體。
與2.1節(jié)中討論的職責鏈模式相比,代理模式的思路和實現(xiàn)方法都比較簡單,唯一需要注意的是,由于需要確保通過統(tǒng)一的接口訪問地形數(shù)據(jù),因此,必須結(jié)合“單實例模式”,確保整個系統(tǒng)運行過程中無論有多少客戶端,DBProxy都只能有一個。
單實例模式(Singleton Pattern),是指保證一個類僅有一個實例,并提供一個訪問它的全局訪問點[3]。其核心思想是讓類自身負責保存它的唯一實例,這個類可以保證沒有其它實例可以被創(chuàng)建,并且它可以提供一個訪問該實例的方法。圖5為作者結(jié)合單實例模式后的代理模式。
圖5 改進后代理模式的UML圖
一個具有很好通用性的三維地形環(huán)境基礎(chǔ)平臺,需要能支持多源異構(gòu)的地形數(shù)據(jù),而僅僅依靠代理模式是不夠的。因為該模式只是解決了如何通過統(tǒng)一接口訪問地形數(shù)據(jù)的問題,至于數(shù)據(jù)庫代理(DBProxy)如何取到這些數(shù)據(jù),數(shù)據(jù)是什么結(jié)構(gòu),存儲于什么位置,這不是數(shù)據(jù)庫代理能夠解決的問題,也并非其職責所在。作者經(jīng)過分析,選擇了“橋接模式”來解決這個問題。
橋接模式(Bridge Pattern),是指將抽象部分與它的實現(xiàn)部分分離,使它們都可以獨立地變化[3]。當一個抽象可能有多個實現(xiàn)時,通常用繼承類協(xié)調(diào)它們,從而將抽象部分與其實現(xiàn)部分緊緊耦合在一起,難以對抽象部分和它的實現(xiàn)部分獨立地進行修改和擴充。而橋接模式則通過將接口和實現(xiàn)部分分離,提高了可擴充性,同時還可以將實現(xiàn)細節(jié)對用戶透明[4]。如圖6所示,為橋接模式的UML圖。
圖6 橋接模式的UML圖
其中:Abstraction接口表示抽象部分,Implementor接口表示實現(xiàn)部分;RefindedAbstraction類表示被提煉的抽象,ConcreteImplementorA和ConcreteImplementorB表示具體的實現(xiàn)。
利用橋接模式的優(yōu)勢,作者設(shè)計了一種基于橋接模式和交換模型的多源異構(gòu)數(shù)據(jù)獲取方式(見圖7所示),基本思路如下:
1)定義一個數(shù)據(jù)提供者接口(DataProvider),為數(shù)據(jù)庫代理組件(DBProxy)提供各種來源的地形數(shù)據(jù)。通過這種方式,在DBProxy和各個異構(gòu)數(shù)據(jù)源(如圖7中的DataProvider1和DataProvider2)之間架起了一座“橋梁”,從而避免了數(shù)據(jù)庫代理直接訪問各個數(shù)據(jù)源,實現(xiàn)了代理與數(shù)據(jù)源的松耦合,這就是橋接模式的主旨所在。
2)定義交換數(shù)據(jù)模型。如圖7中的TransModelDem和TransModelImg,分別表示交換模型中的Dem數(shù)據(jù)和紋理數(shù)據(jù)。設(shè)計交換數(shù)據(jù)模型的目的,是為了使各個DataProvider能在根據(jù)指定的參數(shù)(如地理范圍、分辨率等)獲取到自己內(nèi)部格式的數(shù)據(jù)模型后,將內(nèi)部格式轉(zhuǎn)換為一種統(tǒng)一格式的數(shù)據(jù)模型,返回給數(shù)據(jù)庫代理。這種統(tǒng)一格式的數(shù)據(jù)格式,就是作者所設(shè)計的交換數(shù)據(jù)模型。它實現(xiàn)了數(shù)據(jù)庫代理組件與各異構(gòu)數(shù)據(jù)源之間的松耦合,達到了減小組件粒度,提高重用性的目的。
圖7 基于橋接模式的數(shù)據(jù)獲取結(jié)構(gòu)圖
設(shè)計模式是軟件工程中的重要研究方向,它能有效解決軟件設(shè)計中的可復用性和可擴展性等問題[6]。本文首先分析了三維地形環(huán)境仿真平臺的特點,然后將設(shè)計模式引入平臺的設(shè)計,分別用職責鏈模式、代理模式和橋接模式解決了平臺設(shè)計中存在的3個主要問題。實踐表明,設(shè)計模式可以有效提高軟件的可維護性和可擴展性。
[1]楊雪榕,梁加紅,馮向軍,等.分布式仿真軟件三層設(shè)計模式及應(yīng)用[J].系統(tǒng)仿真學報,2008,20(21):5812-5815.
[2]林舒萍,羅鍵.設(shè)計模式的應(yīng)用研究[J].計算機工程與設(shè)計,2005,26(11):2980-2982.
[3]程杰.大話設(shè)計模式[M].北京:清華大學出版社,2007.
[4]涂建光,邊馥苓.基于設(shè)計模式的組件化GIS軟件開發(fā)方法[J].武漢大學學報:信息科學版,2005,30(1):77-81.
[5]Kim D H,Kim K S,Choi H.The Design and Implementation of Open GIS Service Component.Geoscience and Remote Sensing Symposium,2001,4:1922-1924.
[6]Eric Freeman,Elisabeth Freeman,Kathy Sierra,Bert Bates.Head First設(shè)計模式[M].北京:中國電力出版社,2007:236-372,316-381.