摘 要:工作流系統(tǒng)作為基礎(chǔ)組件應(yīng)該能夠與應(yīng)用程序靈活集成,在設(shè)計(jì)工作流系統(tǒng)中的組織模型架構(gòu)時(shí)應(yīng)重點(diǎn)考慮與應(yīng)用系統(tǒng)的集成方式#65377;設(shè)計(jì)基于工廠模式與反射技術(shù)的組件按需加載模型,降低軟件系統(tǒng)間的耦合#65377;實(shí)現(xiàn)工作流組織模型與不同類型的應(yīng)用程序的良好集成#65377;基于該技術(shù)實(shí)現(xiàn)的項(xiàng)目管理系統(tǒng)在多個(gè)企業(yè)得到成功應(yīng)用#65377;
關(guān)鍵詞:工作流;工廠模式;反射;耦合;按需加載;
中圖分類號(hào):TP311文獻(xiàn)標(biāo)識(shí)碼:A
1 引 言
隨著工作流技術(shù)的快速發(fā)展與逐步成熟,越來越多的應(yīng)用系統(tǒng)將其作為必需的基礎(chǔ)部件#65377;為了將工作流集成到應(yīng)用系統(tǒng)中,許多公司都開發(fā)了自己的工作流產(chǎn)品#65377;但是在開發(fā)過程中,一個(gè)需要重點(diǎn)解決的問題是如何實(shí)現(xiàn)工作流管理系統(tǒng)與應(yīng)用系統(tǒng)的靈活集成#65377;由于工作流管理系統(tǒng)是一個(gè)公共部件,因此,它應(yīng)該能夠很方便地與各種應(yīng)用集成而又不破壞雙方的設(shè)計(jì)架構(gòu),這實(shí)際上是如何降低工作流管理系統(tǒng)與應(yīng)用系統(tǒng)的耦合度的問題#65377;
在J2EE平臺(tái)下,有幾種技術(shù)可以很好地解決這個(gè)問題,如Spring框架#65380;Avalon框架#65380;PicoContainer輕量級(jí)容器等[6]#65377;但在.NET平臺(tái)下,卻沒有相應(yīng)的框架產(chǎn)品#65377;另外,出于對(duì)性能的考慮,應(yīng)用程序中沒有采用上述任何框架,因而需要設(shè)計(jì)一種足夠靈活的組件集成模型#65377;
2 耦合問題的分析
根據(jù)WfMC的定義,一個(gè)完整的工作流模型是由過程模型#65380;組織模型和資源模型構(gòu)成的一個(gè)有機(jī)整體[4]#65377;實(shí)施基于工作流管理系統(tǒng)的應(yīng)用時(shí)一個(gè)非常重要的任務(wù)就是將應(yīng)用程序中的組織模型與工作流中的組織模型集成#65377;但是,由于應(yīng)用程序和工作流產(chǎn)品是由不同團(tuán)隊(duì)開發(fā)的,模型上的差異使得集成相當(dāng)困難#65377;通常采用的方式是在應(yīng)用程序中利用工作流提供的接口將組織數(shù)據(jù)寫入工作流系統(tǒng)中,以實(shí)現(xiàn)流程的工作指派#65377;但這種方式導(dǎo)致組織數(shù)據(jù)在兩個(gè)數(shù)據(jù)庫中重復(fù)存放,需要考慮數(shù)據(jù)的完整性和一致性管理,非常繁瑣#65377;如圖1所示#65377;
重復(fù)意味著耦合[1],這種數(shù)據(jù)庫的重復(fù)造成了兩個(gè)系統(tǒng)間不必要的耦合,它勢(shì)必要求在兩個(gè)數(shù)據(jù)庫之間保持一致,而完成這項(xiàng)工作是非常困難的#65377;一個(gè)自然的想法是去掉工作流環(huán)境中的組織數(shù)據(jù)庫而采用應(yīng)用環(huán)境中的組織數(shù)據(jù)庫作為統(tǒng)一的組織數(shù)據(jù)存儲(chǔ)環(huán)境,這樣就解決了數(shù)據(jù)的一致性問題#65377;但是,在這種方式下,工作流中的組織模型組件需要訪問應(yīng)用環(huán)境的組織模型組件,從而導(dǎo)致工作流組件對(duì)應(yīng)用程序組件的依賴,這顯然是不行的#65377;這是因?yàn)椴煌膽?yīng)用環(huán)境可能具有不同的組織模型和接口,開發(fā)工作流系統(tǒng)時(shí)不可能預(yù)知將和哪個(gè)應(yīng)用程序集成,因而也就無法預(yù)知應(yīng)用程序的組織模型的接口和組件#65377;即使通過制定統(tǒng)一的組織模型接口標(biāo)準(zhǔn),還是需要在工作流組織模型中實(shí)例化應(yīng)用系統(tǒng)的組織模型組件#65377;見圖2#65377;
這實(shí)際上是一個(gè)如何延緩接口實(shí)現(xiàn)的問題,即在開發(fā)工作流組件時(shí)只依賴共同的組織模型接口編程,而組織模型的實(shí)例化則在集成具體應(yīng)用時(shí)完成#65377;
3 按需加載模型
在.NET 平臺(tái)下基于工廠模式和反射技術(shù)的按需加載模型提供了對(duì)這個(gè)問題的一個(gè)解決方案#65377;思路是:調(diào)用者通過工廠對(duì)象來實(shí)例化被調(diào)用組件,但由于被調(diào)用組件的可變性,不能在工廠代碼中固化實(shí)例化具體組件的代碼,因此我們借助于反射技術(shù)中組件的動(dòng)態(tài)裝載技術(shù),通過配置文件設(shè)置要實(shí)例化的組件,再由工廠類讀取配置,根據(jù)配置決定具體實(shí)例化哪個(gè)組件,這樣就實(shí)現(xiàn)了組件的按需加載#65377;
計(jì)算技術(shù)與自動(dòng)化2007年6月第26卷第2期方 俊等:按需構(gòu)造的工作流系統(tǒng)組織模型3.1 工廠模式
在傳統(tǒng)的編程方式中,控制權(quán)是由調(diào)用者掌握,即調(diào)用誰是由調(diào)用者決定的,因此,在調(diào)用者代碼中就包含了創(chuàng)建被調(diào)用者實(shí)例的代碼,這樣就構(gòu)成了調(diào)用者對(duì)被調(diào)用者的依賴#65377;見下面的代碼(以下代碼都采用C#編寫):
在類A的代碼中定義了類B的引用變量,這種依賴是在編譯期引入的(前期綁定)#65377;根據(jù)文獻(xiàn)[3],這種依賴是造成軟件僵化(Rigidity)#65380;脆弱(Fragility)的主要原因#65377;DIP原則指出應(yīng)該在調(diào)用者和被調(diào)用者間加入抽象接口,使調(diào)用者和被調(diào)用者都依賴于抽象接口,這樣,只要接口保持不變,被調(diào)用者的改變不會(huì)影響調(diào)用者,從而解決了軟件的僵化脆弱問題#65377;見圖3:
但是,引入抽象接口并沒有將調(diào)用者和被調(diào)用者完全解耦,只是將兩者間的依賴由前期綁定改成了后期綁定#65377;在調(diào)用者代碼中還存在直接創(chuàng)建被調(diào)用者實(shí)例的代碼#65377;見下面代碼:假設(shè)IB是一個(gè)接口,類B實(shí)現(xiàn)了接口IB#65377;
這種A和B的依賴關(guān)系導(dǎo)致了對(duì)組件B的調(diào)用的不可變性,如果存在多個(gè)實(shí)現(xiàn)了IB接口的類可以完成類似工作,在這種方式下就沒有辦法根據(jù)需要有選擇地調(diào)用所需的類#65377;GoF的《設(shè)計(jì)模式》中給出的工廠模式很好地解決了這個(gè)問題#65377;
簡(jiǎn)單工廠模式[5]引入一個(gè)工廠類,負(fù)責(zé)根據(jù)需要來創(chuàng)建被調(diào)用者的實(shí)例,調(diào)用者通過工廠類獲得調(diào)用者實(shí)例#65377;這樣,在調(diào)用者代碼中就沒有對(duì)被調(diào)用者的直接引用,從而實(shí)現(xiàn)了調(diào)用者和被調(diào)用者間的真正解耦#65377;通常,工廠類時(shí)根據(jù)傳入的參數(shù)來決定創(chuàng)建哪個(gè)調(diào)用者實(shí)例的#65377;見圖4:
但是工廠模式對(duì)于有些情況卻無能為力,比如“耦合問題分析”一節(jié)中描述的組織模型調(diào)用問題:在編寫工作流軟件組件時(shí)無法預(yù)知將會(huì)和哪個(gè)應(yīng)用程序集成,因此無法采用上述的工廠模式來實(shí)例化具體的應(yīng)用程序中的組織模型組件#65377;必須有一種機(jī)制使得工廠可以在運(yùn)行時(shí)選擇組件并對(duì)其進(jìn)行實(shí)例化,也就是我們?cè)诠S中不必固定地寫入要實(shí)例化的類的名稱,如圖4中的B1#65380;B2#65380;B3那樣#65377;
這種機(jī)制可以通過.NET平臺(tái)的反射技術(shù)實(shí)現(xiàn)#65377;
3.2 在工廠模式中使用反射
使用反射技術(shù)可以動(dòng)態(tài)地裝載程序集,并從程序集動(dòng)態(tài)地創(chuàng)建類型的實(shí)例[2]#65377;將反射技術(shù)與工廠模式結(jié)合,就可以實(shí)現(xiàn)組件的按需加載#65377;方法是:通過將組件的信息寫入一個(gè)XML文件,在工廠類中讀取配置文件并根據(jù)讀取的組件信息動(dòng)態(tài)裝入組件,然后實(shí)例化所需類#65377;由于組件可以是不同的團(tuán)隊(duì)根據(jù)公共接口標(biāo)準(zhǔn)實(shí)現(xiàn)的,因而也就實(shí)現(xiàn)了與不同應(yīng)用系統(tǒng)的集成#65377;
依照上述思路,將工廠模式中的工廠類擴(kuò)展成一個(gè)服務(wù)容器,該容器根據(jù)配置文件動(dòng)態(tài)裝載組件,并將組件中的類封裝成一個(gè)個(gè)服務(wù)存放在服務(wù)集合中#65377;容器提供一個(gè)查找方法可以根據(jù)條件從集合中找到所需類的服務(wù),返回給調(diào)用者,調(diào)用者通過服務(wù)對(duì)象可以獲得所需的類的實(shí)例#65377;注意,被封裝的類必須實(shí)現(xiàn)公共的接口#65377;見圖5#65377;
從圖5可以看到,由于采用了反射的動(dòng)態(tài)裝載機(jī)制,調(diào)用者(A)與被調(diào)用者(B1#65380;B2#65380;B3)之間沒有了依賴關(guān)系,同時(shí)工廠類也沒有與任何具體的被調(diào)用者類存在依賴關(guān)系,這樣工廠就可以實(shí)現(xiàn)對(duì)被調(diào)用者組件的按需裝配#65377;只要組件實(shí)現(xiàn)了IB接口,就可以通過配置文件將其作為服務(wù)裝配到工廠中,調(diào)用者可以調(diào)用工廠類的方法(GetService)查找所需被調(diào)用者的服務(wù),通過該服務(wù)提供的方法(GetInstance)可以獲取被調(diào)用者類的實(shí)例#65377;
工廠類以單例模式[5]實(shí)現(xiàn),目的是保證服務(wù)容器的一致性#65377;在其中實(shí)現(xiàn)一個(gè)靜態(tài)方法CreateFactoryInstance,用于獲得工廠實(shí)例#65377;在工廠類的構(gòu)造函數(shù)中讀取配置文件,獲得當(dāng)前系統(tǒng)配置的組件信息,并將這些組件信息封裝成一個(gè)個(gè)的服務(wù),存放在集合Services中#65377;在封裝一個(gè)服務(wù)時(shí)需要有接口#65380;實(shí)現(xiàn)類#65380;程序集文件等信息,因此,在配置文件中每條配置信息需要有上述內(nèi)容#65377;下面是一個(gè)配置文件的例子#65377;
其中,InterfaceName是接口的完全限定名,ClassName是實(shí)現(xiàn)類的完全限定名,AssemblyFile是程序集文件名#65377;
在工廠類中集合Services存放的服務(wù)對(duì)象是Service的實(shí)例#65377;Service類中存放有接口名#65380;類名#65380;程序集文件名,這些信息是在工廠封裝服務(wù)時(shí)通過構(gòu)造函數(shù)存入的#65377;見下面代碼:
為了讓調(diào)用者可以獲得所需的服務(wù),工廠類中還提供了方法GetService,它根據(jù)調(diào)用者提供的接口名在集合Services中查找對(duì)應(yīng)的服務(wù)#65377;見下面代碼:
3.3 組織模型的按需構(gòu)造
有了上述的工廠,我們可以在工作流系統(tǒng)中定義組織模型的接口,并要求與之集成的應(yīng)用程序?qū)崿F(xiàn)這些接口,然后在配置文件中對(duì)這些信息進(jìn)行配置,這樣,在工作流系統(tǒng)中就可以通過工廠類對(duì)象動(dòng)態(tài)獲得應(yīng)用程序的組織模型組件的實(shí)例,并通過這些實(shí)例完成對(duì)組織數(shù)據(jù)的操作#65377;下面以組織模型中的部門為例說明其實(shí)現(xiàn):
首先在工作流系統(tǒng)中定義接口IDepartment,然后在應(yīng)用程序中實(shí)現(xiàn)該接口,假設(shè)實(shí)現(xiàn)類為Department,并且編譯后的組織模型組件為Organization.dll,則配置文件的信息如上節(jié)所示#65377;
當(dāng)在工作流系統(tǒng)中需要訪問組織數(shù)據(jù)時(shí),可以采用下述代碼獲取Department的實(shí)例:
在工作流中對(duì)組織數(shù)據(jù)的訪問完全是透明的,它不必在編譯期連接確定的組件,而是通過在執(zhí)行時(shí)動(dòng)態(tài)裝載特定組件實(shí)現(xiàn)對(duì)組織數(shù)據(jù)的訪問#65377;在本實(shí)例中我們并沒指定應(yīng)用程序是什么,它可以是工程項(xiàng)目管理系統(tǒng)也可以是ERP系統(tǒng),只要實(shí)現(xiàn)了工作流中定義的組織模型接口,就可以將其寫入配置文件讓工作流系統(tǒng)調(diào)用#65377;這樣,極大地增強(qiáng)了工作流系統(tǒng)的靈活性,方便其與各種應(yīng)用系統(tǒng)的集成#65377;
4 結(jié)束語
通過將工廠模式與反射技術(shù)結(jié)合實(shí)現(xiàn)組件的動(dòng)態(tài)加載,解決了工作流系統(tǒng)的組織模型與應(yīng)用系統(tǒng)的組織模型的集成難題,使得基于不同數(shù)據(jù)庫系統(tǒng)開發(fā)的工作流系統(tǒng)和應(yīng)用系統(tǒng)可以很好的集成在一起#65377;基于這一技術(shù)實(shí)現(xiàn)的工作流系統(tǒng)已在多個(gè)鋼鐵企業(yè)的工程項(xiàng)目管理系統(tǒng)中得到了成功的應(yīng)用#65377;
注:本文中所涉及到的圖表、注解、公式等內(nèi)容請(qǐng)以PDF格式閱讀原文。