三年前,聽當時的師兄推薦,買了蔣波濤的一本關於GIS插件框架的書。當時一邊看書一邊將其中的例子完整的實現了一遍,收益匪淺。後來由於項目需要,也做過一個插件的C/S系統,用的是微軟提供的MEF框架。在這個系統中,把蔣波濤在他的書中沒有涉及到的插件和插件的通信完成了。不過,蔣波濤的那本書,涉及到了插件系統的很多底層內容,其中關於插件引擎的設計尤其值得學習。近來,我將自己當年實現的那個例子進行了一個總結,和大家一起分享。
(1).框架分為宿主程序和插件對象兩部分
(2).兩部分交互基於一種公共的通信契約
(3).宿主程序可以獨立存在
(1).可以在無需對程序進行重新編譯和發布的條件下擴展程序的功能
(2).可以在不需要程序源代碼的環境下為程序增加新的功能
(3).在一個程序的業務邏輯不斷發生改變、新的規則頻頻加入時能夠靈活適應
(1).基於動態鏈接庫DLL的插件
(2).基於COM的插件
(3).基於反射技術的插件
接口分為:
宿主接口:IApplicaiton
插件接口:IPlugin(ICommand,Itool, IMenuDef,IToolBarDef,IDockableWindowDef)和不是繼承於Ipluging的IItemDef
本章中,對繼承於IApplication的Application和繼承於ItemDef的ItemDef類進行了實現。類圖如下:
在實例化的插件還沒有被添加到宿主中時,需要一個寄存這些實例化的插件的宿主。
於是,我們在設計完插件接口後,還得做一個設計插件容器的工作。此容器只能存放繼承於Iplugin的類。
首先:
繼承CollectionBase抽象類。
因為CollectionBase已經實現了Ilist,Icolloction和Ienumerable等三個接口,為我們解決了大部分問題。
(其中主要重點是要覆蓋一個新的GetEnumerator()方法,且此方法返回的是一個實現了IEnumerator接口的類.如果在重寫這個方法時已經利用yield實現了迭代功能,則第二步可以跳過)。
然後:
寫那個繼承並實現了IEnumerator接口的類。(主要是重寫Current,MoveNext,,Reset三個函數)
以上我們設計了通訊接口和接口容器,為什麼說插件只有實現了這些接口中的一個才能被識別呢?
因為我們的接口引擎(PluginEngine)只能對這些接口進行識別。
那麼何為接口引擎呢?
簡單點說,在本系統中,就是利用反射後得到的每個TYPE的InterFace必須是我們以上規定的幾個接口才能被識別和做出反應。
反射機制是我們這個插件系統的核心技術。
它使得這些類都可以被動態加載和調用。
(1).本系統首先利用Directory.GetFiles()函數得到目標文件夾裡的所有DLL文件。
(2).利用反射函數Assemly.LoadFrom加載文件(得到若干程序集)。再利用程序集的GetTypes()得到Type[]數組。
(3).最後利用Type類的GetInterfaces()得到每一個類所繼承的接口。利用switch檢查這個類是否繼承過自定義的那些接口。若實現過,則利用Activator.CreateInstance(Type _type)這個方法來實例化這個類。最後將其加入到插件容器PluginCollection中。