張德明
(中國鐵道科學(xué)研究院通信信號研究所,北京100081)
模塊化是軟件設(shè)計(jì)中需要達(dá)到的主要目標(biāo)之一。相對于傳統(tǒng)的面向過程的語言將數(shù)據(jù)結(jié)構(gòu)與算法分開的方式,面向?qū)ο蟮脑O(shè)計(jì)方法將相關(guān)的數(shù)據(jù)結(jié)構(gòu)與算法作為一個(gè)對象進(jìn)行封裝,形成一個(gè)擁有自己狀態(tài)以及行為的整體。在設(shè)計(jì)對象時(shí),通過有效地將相互關(guān)聯(lián)的數(shù)據(jù)結(jié)構(gòu)與行為進(jìn)行封裝,而向外只提供必要的接口,從而達(dá)到強(qiáng)內(nèi)聚松藕合的效果,也就達(dá)到了模塊化的目標(biāo)。
在單線程環(huán)境下,采用對象的方式確實(shí)能夠?qū)崿F(xiàn)有效的封裝。然而,當(dāng)軟件在多線程環(huán)境中運(yùn)行時(shí),對象在封裝上則會遇到并發(fā)范圍的問題。
圖1 對象交互的圖示
圖1展示了一個(gè)簡單多線程環(huán)境。其中,有A,B,C3個(gè)以面向?qū)ο蠓椒ㄟM(jìn)行封裝的對象,另外有兩個(gè)環(huán)境線程。系統(tǒng)期望兩個(gè)線程能夠在3個(gè)對象的并發(fā)運(yùn)行中,完成系統(tǒng)的功能。我們可以看到,對象B雖然作為一個(gè)獨(dú)立的對象,封裝了自己的結(jié)構(gòu)和行為。但是,由于它同時(shí)被兩個(gè)線程訪問,這樣,在對象C和A與B進(jìn)行交互時(shí),必須要考慮許多線程同步的因素,造成對象間訪問時(shí)接口復(fù)雜,也就是增強(qiáng)了對象間的耦合性。當(dāng)系統(tǒng)的對象更多,并發(fā)線程更多時(shí),對象間的耦合將會成倍增加,軟件的模塊化目標(biāo)將遇到嚴(yán)重的挑戰(zhàn)。
車次追蹤系統(tǒng)是調(diào)度監(jiān)督以及調(diào)度集中系統(tǒng)中一個(gè)重要的組成部分,車次追蹤系統(tǒng)根據(jù)現(xiàn)場采集的站場表示信息,無線車次號信息,行調(diào)臺下達(dá)的計(jì)劃信息,以及人工車次修改等信息,通過綜合運(yùn)算,對追蹤區(qū)段的列車進(jìn)行識別、跟蹤和校核,并在此基礎(chǔ)上提供自動(dòng)報(bào)點(diǎn),列車位置報(bào)告等信息。
在實(shí)際設(shè)計(jì)中,車次追蹤系統(tǒng)作為調(diào)度系統(tǒng)應(yīng)用服務(wù)器中的一個(gè)模塊。作為整體的應(yīng)用服務(wù)器,除了提供車次信息相關(guān)運(yùn)算和服務(wù)外,還要提供通信信息轉(zhuǎn)發(fā)、表示信息處理和進(jìn)路信息處理等功能。
當(dāng)把應(yīng)用服務(wù)器作為系統(tǒng)的環(huán)境,而將通信轉(zhuǎn)發(fā)、車次追蹤和進(jìn)路控制分別作為一個(gè)重量級的對象時(shí),將得到一個(gè)類似圖1的系統(tǒng)結(jié)構(gòu)環(huán)境,見圖2。
圖2 車次追蹤的應(yīng)用服務(wù)器環(huán)境框圖
在圖2的應(yīng)用服務(wù)環(huán)境中,系統(tǒng)要求應(yīng)用服務(wù)器所提供的各個(gè)功能,包括車次追蹤,通信轉(zhuǎn)發(fā),以及進(jìn)路控制等都能夠并行運(yùn)行,因此,系統(tǒng)中必須引入多個(gè)線程。 同時(shí),由于各個(gè)服務(wù)模塊之間需要交互,以傳統(tǒng)面向?qū)ο竽J竭M(jìn)行設(shè)計(jì),必然將多個(gè)線程引入對象中,造成同步的困難,增強(qiáng)了系統(tǒng)的藕合性。如何保證車次追蹤系統(tǒng)設(shè)計(jì)的模塊化,同時(shí)又保證模塊的并行性,如前面引用中提到的,是對系統(tǒng)設(shè)計(jì)方法的一個(gè)挑戰(zhàn)。
我們以圖3來說明主動(dòng)對象模型。
圖3 主動(dòng)對象模型
圖3中的對象分為兩種,其中A,B,C同以前的對象一樣,只能被別的線程被動(dòng)調(diào)用,稱之為被動(dòng)對象。另外一種對象,作為A,B,C3個(gè)對象的運(yùn)行環(huán)境,它將系統(tǒng)的線程進(jìn)行了封裝,并提供了對外接口的郵箱,稱之為主動(dòng)對象。
系統(tǒng)的運(yùn)轉(zhuǎn)過程如下:當(dāng)外界有任務(wù)或者指令要主動(dòng)對象來完成時(shí),外界系統(tǒng)將任務(wù)以消息形式發(fā)送到主動(dòng)對象的郵箱隊(duì)列中,主動(dòng)對象的封裝線程則一直對其郵箱隊(duì)列進(jìn)行監(jiān)視,一旦發(fā)覺郵箱中有消息,將取出消息進(jìn)行處理。當(dāng)任務(wù)比較復(fù)雜時(shí),主動(dòng)對象將消息分發(fā)給相關(guān)的被動(dòng)對象,讓其進(jìn)行相應(yīng)處理。
可以看出,在主動(dòng)對象模型中,因?yàn)橐肓酥鲃?dòng)對象,對任務(wù)線程進(jìn)行了封裝,這樣就給其它被動(dòng)對象提供了一個(gè)單線程的環(huán)境。在對A,B,C等各個(gè)被動(dòng)對象進(jìn)行算法設(shè)計(jì)時(shí),只需要考慮基本的業(yè)務(wù)邏輯,而不需要考慮系統(tǒng)的并發(fā)性問題,有效地降低了系統(tǒng)的耦合性,增強(qiáng)了系統(tǒng)的模塊化。
圖4給出基于主動(dòng)對象模型車次追蹤模塊的主框架結(jié)構(gòu)。其中主要包含4個(gè)部分:接口,隊(duì)列,線程以及處理。
圖4 車次追蹤主框架結(jié)構(gòu)
接口部分將所有輸入輸出進(jìn)行封裝,其中CallIn供其它系統(tǒng)進(jìn)行調(diào)用,將表示信息,計(jì)劃信息等輸入到車次追蹤系統(tǒng),CallIn的處理就是將這些調(diào)用以消息的形式存放到消息隊(duì)列中。
CallOut封裝了車次追蹤模塊的輸出部分,外界系統(tǒng)通過重載CallOut方法,從而實(shí)現(xiàn)對車次號和報(bào)點(diǎn)等信息的獲取。
隊(duì)列部分完成主動(dòng)對象模型中的郵箱功能。所有外界的信息要傳遞到車次追蹤系統(tǒng),均需要以消息形式壓入隊(duì)列。同時(shí),封裝線程部分對隊(duì)列進(jìn)行不間斷監(jiān)視,一旦發(fā)現(xiàn)隊(duì)列中有數(shù)據(jù),將以先進(jìn)現(xiàn)出的方式從中取出。
由于隊(duì)列部分同時(shí)要被外部線程和模塊內(nèi)部線程訪問,因此,在隊(duì)列訪問時(shí)設(shè)置同步機(jī)制。
系統(tǒng)通過將操作系統(tǒng)提供的線程進(jìn)行封裝,從而形成只在車次追蹤模塊內(nèi)部運(yùn)行的線程,當(dāng)對象生成時(shí),生成并啟動(dòng)線程,當(dāng)對象消亡時(shí),終止并結(jié)束線程。
系統(tǒng)線程在對象生存期不間斷地運(yùn)轉(zhuǎn),給車次追蹤的業(yè)務(wù)邏輯處理對象提供運(yùn)行環(huán)境,同時(shí)從消息隊(duì)列中獲取消息,并將這些消息分發(fā)給實(shí)現(xiàn)部分進(jìn)行具體處理。
處理部分是車次追蹤算法的核心,包含大量站場相關(guān)的數(shù)據(jù)結(jié)構(gòu)和處理類。這些處理類由封裝線程進(jìn)行調(diào)用,對接收到的表示信息、無線車次號信息以及計(jì)劃信息等進(jìn)行綜合分析,運(yùn)算得出列車車次號位置信息以及報(bào)點(diǎn)等信息,將這些信息通過CallBack函數(shù)回調(diào)輸出。
本文引入主動(dòng)對象模型,將車次追蹤的具體實(shí)現(xiàn)與并發(fā)處理分開,允許在進(jìn)行算法設(shè)計(jì)時(shí)不用考慮系統(tǒng)的并行性,有效地降低了系統(tǒng)設(shè)計(jì)的復(fù)雜度。在滿足系統(tǒng)實(shí)時(shí)性特征的情況下,保證了系統(tǒng)的獨(dú)立性和模塊化。
[1] 朱冰,梅宏,楊芙清. 基于事件驅(qū)動(dòng)的主動(dòng)對象模型[J] . 軟件學(xué)報(bào),1996(3).
[2] F.Buschmann, K.Henney, D.C.Schmidt. Patten-Oriented Software Architecture, Volume 4: A Pattern Language for Distributed Computing[M] . John Wiley & Sons, 2007: 365-367.