(1)從底層設計,探討插件式GIS框架的實現


文章版權由作者李曉暉和博客園共有,若轉載請於明顯處標明出處:http://www.cnblogs.com/naaoveGIS/

 

研一時,聽當時的師兄推薦,買了蔣波濤的一本關於GIS插件框架的書。當時一邊看書一邊將其中的例子完整的實現了一遍,收益匪淺。后來由於項目需要,也做過一個插件的C/S系統,用的是微軟提供的MEF框架。在這個系統中,把蔣波濤在他的書中沒有涉及到的插件和插件的通信完成了。不過,蔣波濤的那本書,涉及到了插件系統的很多底層內容,其中關於插件引擎的設計尤其值得學習。近來,我將自己當年實現的那個例子進行了一個總結,和大家一起分享。

1.插件式框架的組成

(1).框架分為宿主程序和插件對象兩部分

(2).兩部分交互基於一種公共的通信契約

(3).宿主程序可以獨立存在

2.使用插件的原因

(1).可以在無需對程序進行重新編譯和發布的條件下擴展程序的功能

(2).可以在不需要程序源代碼的環境下為程序增加新的功能

(3).在一個程序的業務邏輯不斷發生改變、新的規則頻頻加入時能夠靈活適應

3.插件的一般實現技術

(1).基於動態鏈接庫DLL的插件

(2).基於COM的插件

(3).基於反射技術的插件

4.細談本框架的實現

4.1.設計全部並實現部分接口

接口分為:

宿主接口:IApplicaiton

插件接口:IPlugin(ICommand,Itool, IMenuDef,IToolBarDef,IDockableWindowDef)和不是繼承於Ipluging的IItemDef

本章中,對繼承於IApplication的Application和繼承於ItemDef的ItemDef類進行了實現。類圖如下:

 

 

 

 

 

4.2制作插件容器

在實例化的插件還沒有被添加到宿主中時,需要一個寄存這些實例化的插件的宿主。

於是,我們在設計完插件接口后,還得做一個設計插件容器的工作。此容器只能存放繼承於Iplugin的類。

4.2.1設計PluginCollection

首先:

繼承CollectionBase抽象類。

因為CollectionBase已經實現了Ilist,Icolloction和Ienumerable等三個接口,為我們解決了大部分問題。

(其中主要重點是要覆蓋一個新的GetEnumerator()方法,且此方法返回的是一個實現了IEnumerator接口的類.如果在重寫這個方法時已經利用yield實現了迭代功能,則第二步可以跳過)。

然后:

寫那個繼承並實現了IEnumerator接口的類。(主要是重寫Current,MoveNext,,Reset三個函數)

4.3設計PluginEngine中的反射機制

以上我們設計了通訊接口和接口容器,為什么說插件只有實現了這些接口中的一個才能被識別呢?

因為我們的接口引擎(PluginEngine)只能對這些接口進行識別。

那么何為接口引擎呢?

簡單點說,在本系統中,就是利用反射后得到的每個TYPE的InterFace必須是我們以上規定的幾個接口才能被識別和做出反應。

 

4.3.1細解動態加載和對象生成

反射機制是我們這個插件系統的核心技術。

它使得這些類都可以被動態加載和調用。

(1).本系統首先利用Directory.GetFiles()函數得到目標文件夾里的所有DLL文件。

(2).利用反射函數Assemly.LoadFrom加載文件(得到若干程序集)。再利用程序集的GetTypes()得到Type[]數組。

(3).最后利用Type類的GetInterfaces()得到每一個類所繼承的接口。利用switch檢查這個類是否繼承過自定義的那些接口。若實現過,則利用Activator.CreateInstance(Type _type)這個方法來實例化這個類。最后將其加入到插件容器PluginCollection中。

 

4.4插件的分類

設置五個接口字典容器,分別是裝ICommand,ITool,IToolBarDef,IMenuDef,IDockableWindowDef的五個容器和一個命令類型容器(其中將存放實現了ICommand和或者ITool的不重復的Category)。

注:這些容器中的Key值都是在實現這些接口的插件的名字。

 

4.5建立宿主框架

利用第三方控件Janus WinForms Controls V3.5來設計界面。

此三方控件中有兩個控件,一個是UICommandManager,一個是UIPanelManager,這兩個控件對插件的插入顯示有很大的幫助

 

此宿主實例化時,首先實例化一個Apllication類,然后再給此實例中的MapControl,PageControl,MainPlantform的重要屬性賦值。

所以通過這個被復制了的實例,宿主和插件的交互就不難實現了。

4.6插件獲取

這是一個比較大的方面,也是核心之一了。也便是,怎么樣能讓宿主得到還保留在插件容器中的插件,並能顯示在宿主中?

1.因為Command和Tool在UI上是同一類型,所以合在一起獲取。

獲取中,有兩個地方要注意:一個是要使實例Create(hook ),即把宿主的相關信息類Application傳遞過去。第二個是,注冊系統定義事件。例如UICommand+=new CommandEventHandler(UICommand_Click);

2.同理分別對繼承了IMenuDef,IToolBarDef以及IDockableWindowDef的對象進行獲取。

注:浮動窗體是由UIPanelManager進行托管的。也就是將懸浮框中的ChildHWND(Control類)加入到新panel中的panelContainer.Controls中。

4.7插件對象的事件處理

上一個步驟中,我們把一個未定義的事件處理方法通過自帶委托注冊到了Click事件中了。

那么這一節我們將具體來寫這個事件處理方法。Command是交互的,Tool是不交互的。所以編寫起來有很大差別。

這兩個處理函數中,有兩個共同的關鍵點:一個是利用e(CommandEventArgs類)的e.Command.Key得到在相關插件字典容器中放置的對象。第二個是都要觸發對象的Click函數。

4.8框架插件設計

 

這節是系統以后也可以繼續擴充的地方。

此處重點抓住cAddData這個插件的實現。

此類首先繼承Icommand這個接口。在宿主窗體加載獲取各插件而觸發的create(Iapplication hook)方法中,調用Engine自帶的ControlsAddDataCommandClass()類,並將其hook到傳遞過來的宿主的MapControl上去即可。

 

4.9宿主程序的高級設計

可以對宿主程序本身進行一些高級設計。比如使得mapControl和PageControl聯動顯示。比如制定TocControl的浮動菜單或者開發要素數據的查詢顯示等。

注意:此些設計都是對宿主本身而設計的,跟插件沒關系。是最大程度上的利用宿主窗體本身。

4.10框架輔助組件框架庫設計

此節完全是為了更方便的開發框架或其插件本身而設計的。

在此部分,可以把很多以后可能會用到的方法進行編寫以及封裝,以后開發便可以直接調用。

可以稱本部分為系統開發包(SDK),但是此部分並非系統必備。

4.11系統發布

系統發布時首先要確定一個空機器上需要運行此系統起碼需要哪些基本的平台。

此系統運行時對方機器上起碼該裝有:.NET 3.0 Framework可再分發組件包,Janus System UI V3.5 和ArcGIS Engine10 Runtime

然后利用InstallShield Express X來打包。

5結果展示

 

6.本框架的優劣及展望

6.1優勢

本框架為純底層開發,移植性和通用性比較好。具有一般的插件所具有的其他特點,例如易擴展,有一定的解耦性。符合面向接口和依賴倒轉的編程思想,在本框架中,還集成了命令模式、觀察者模式、遍歷模式以及外觀模式,單例模式。

6.2劣勢

本框架划分的粒度太細,這樣容易使類爆炸式增長。

本框架只實現了插件與宿主之間的通信,而沒有實現插件與插件之間的通信。

6.3展望

解決插件與插件之間的通信,可單獨做一個復雜通信的插件,然后其他插件均引用此插件。利用觀察者模式,在宿主中加載插件后,便能實現事件注冊,進而實現插件之間的通信。

同時,很多框架都實現了插件的編程思想。比利用Spring的依賴注入和微軟提供的MEF所有的依賴注入,均能實現插件系統。

 

                                                                 -----歡迎轉載,但保留版權,請於明顯處標明出處:http://www.cnblogs.com/naaoveGIS/

                                                                           如果您覺得本文確實幫助了您,可以微信掃一掃,進行小額的打賞和鼓勵,謝謝 ^_^

                                    


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM