目 錄
第七章 外部接口的設(shè)計(jì)... 2
7.1 插件接口... 2
7.2 圖形顯示接口... 3
7.3 數(shù)據(jù)導(dǎo)出接口... 5
7.4 服務(wù)組件接口... 6
7.5 插件管理器... 8
7.6 框架整合、重構(gòu)... 9
7.7 小結(jié)... 10
開發(fā)者不僅可以二次開發(fā)設(shè)備驅(qū)動(dòng),還可以二次開發(fā)自定義圖形顯示形式、
自定義數(shù)據(jù)導(dǎo)出格式和多種業(yè)務(wù)服務(wù),并且設(shè)備驅(qū)動(dòng)接口與這三種接口進(jìn)行事件響應(yīng)和數(shù)據(jù)交互。
圖形顯示接口、數(shù)據(jù)導(dǎo)出接口和服務(wù)組件接口都繼承自統(tǒng)一的插件接口(iplugins),主要是方便管理和擴(kuò)展。插件接口的代碼定義如下:
public interface IPlugins : IDisposable{ /// <summary> /// 服務(wù)Key,要求唯一 /// </summary> string ThisKey { get; } /// <summary> /// 服務(wù)名稱 /// </summary> string ThisName { get; } /// <summary> /// 更新設(shè)備數(shù)據(jù),用于接收來自設(shè)備驅(qū)動(dòng)的數(shù)據(jù)信息 /// </summary> /// <param name="devid">設(shè)備ID</param> /// <param name="obj">設(shè)備對象</param> void UpdateDevice(int devid, object obj); /// <summary> /// 移除設(shè)備,當(dāng)框架平臺(tái)刪除設(shè)備的時(shí)候進(jìn)行響應(yīng)。 /// </summary> /// <param name="devid">設(shè)備ID</param> void RemoveDevice(int devid);}
圖形顯示接口、數(shù)據(jù)導(dǎo)出接口和服務(wù)組件接口與插件接口的繼承關(guān)系如下圖:
設(shè)備驅(qū)動(dòng)只要有更新數(shù)據(jù)就會(huì)通過事件把數(shù)據(jù)傳送到UpdateDevice接口里,這個(gè)接口內(nèi)部到底怎么處理完全由二次開發(fā)者來決定。當(dāng)觸發(fā)設(shè)備驅(qū)動(dòng)的刪除事件,就會(huì)調(diào)用RemoveDevice接口,以刪除、釋放資源。
框架平臺(tái)通訊設(shè)備驅(qū)動(dòng)把數(shù)據(jù)采集上來的只是原始數(shù)據(jù),經(jīng)過處理后要形成業(yè)務(wù)數(shù)據(jù),那么就會(huì)有顯示、分析、查詢、打印、報(bào)表等業(yè)務(wù)功能,并且針對同樣的數(shù)據(jù)信息,不同的用戶要求處理的方式有很大的不同。這部分功能變動(dòng)很大,但是又不能每次有變動(dòng)就要去修改框架平臺(tái),因?yàn)榭蚣苁?ldquo;穩(wěn)定”的部分,形成版本控制后就不隨便改變了。
基于這樣考慮,作為框架要提供一個(gè)機(jī)制,能夠加載二次開發(fā)者設(shè)計(jì)的UI窗體。用于顯示采集終端設(shè)備的數(shù)據(jù),可以把不同類型設(shè)備的數(shù)據(jù)以多種形式集成顯示在不同界面上。方便為用戶提供多種的、更友好的人機(jī)交互界面。
首先,框架平臺(tái)不能在啟動(dòng)的時(shí)候就顯示所有UI窗體,具體要顯示哪個(gè)UI窗體完全由用戶自己決定,所以,我們要通過配置文件的形式把二次開發(fā)的組件信息加載到菜單里,提供可觸發(fā)的顯示事件入口,如下圖:
其次,那么以什么樣的形式顯示窗體呢?像很多管理系統(tǒng)一樣,我們采用Form Tab的方式顯示,如下圖:
UI部分的設(shè)計(jì)就這樣了,但是從業(yè)務(wù)角度我們要考慮兩件事:(1)在二次開發(fā)的窗體上單擊鼠標(biāo)右鍵事件時(shí)要顯示相應(yīng)設(shè)備的上下文菜單,也就是說要調(diào)用IRunDevice設(shè)備驅(qū)動(dòng)的ShowContextMenu函數(shù),要在IGraphiCSShow接口中提供MouseRightContextMenuHandler事件,以驅(qū)動(dòng)調(diào)用ShowContextMenu函數(shù)顯示上下文菜單。(2)當(dāng)單擊菜單項(xiàng)的時(shí)候,會(huì)以Tab的形式顯示窗體,但是當(dāng)多次單擊后是不能多次顯示UI窗體的,所以要有一個(gè)管理器(GraphicsShowController),通過接口的ThisKey屬性判斷當(dāng)前顯示的UI窗體是否存在,如果不存在,那么就顯示該UI窗體,否則退出操作;既然有一個(gè)管理器,當(dāng)關(guān)閉窗體的時(shí)候,需要把該UI窗體實(shí)例從管理器中刪除掉,避免無法再次顯示窗體,因?yàn)樗恢贝嬖谟诠芾砥髦小K赃€需要在接口中定義一個(gè)關(guān)閉窗體的事件GraphicsShowClosedHandler,釋放窗體資源后從管理器中刪除實(shí)例。
至此,自定義窗體顯示部分就設(shè)計(jì)完畢了,IGraphicsShow接口定義代碼如下:
public interface IGraphicsShow : IPlugins{ /// <summary> /// 關(guān)閉窗體事件時(shí)發(fā)生 /// </summary> event GraphicsShowClosedHandler GraphicsShowClosedHandler; /// <summary> /// 單擊右鍵 /// </summary> event MouseRightContextMenuHandler MouseRightContextMenuHandler;}
在數(shù)據(jù)集成系統(tǒng)項(xiàng)目中,要么是集成其他廠家的設(shè)備數(shù)據(jù),要么是其他廠家集成自己家的設(shè)備數(shù)據(jù),在沒有統(tǒng)一的標(biāo)準(zhǔn)前提下,會(huì)有各種集成數(shù)據(jù)的格式。為了滿足此類的場景,為設(shè)備導(dǎo)出數(shù)據(jù)專門設(shè)計(jì)了接口,開發(fā)者可以繼承該接口,設(shè)備在處理完數(shù)據(jù)后,會(huì)把數(shù)據(jù)自動(dòng)傳輸?shù)皆摻涌冢梢园匆?guī)定的數(shù)據(jù)格式進(jìn)行輸出了。
對設(shè)備驅(qū)動(dòng)實(shí)時(shí)數(shù)據(jù)導(dǎo)出,可以把一類的設(shè)備數(shù)據(jù)導(dǎo)出成多種數(shù)據(jù)格式。
導(dǎo)出數(shù)據(jù)插件可以通過配置文件進(jìn)行加載,只要設(shè)備驅(qū)動(dòng)有數(shù)據(jù)更新,就把數(shù)據(jù)通過事件傳遞給導(dǎo)出數(shù)據(jù)接口。不在配置文件中配置插件信息,則程序不進(jìn)行加載,不進(jìn)行導(dǎo)出操作。所以,這種事務(wù)性的服務(wù)不需要界面來完成,可以在宿主程序啟動(dòng)時(shí)通過代碼來完成。
IExportData數(shù)據(jù)導(dǎo)出接口代碼定義如下:
public interface IExportData:IPlugins{ /// <summary> /// 格式化數(shù)據(jù) /// </summary> /// <param name="devid"></param> /// <param name="obj"></param> /// <returns></returns> object FormatDataString(int devid, object obj, DeviceType devicetype);}
圍繞著設(shè)備驅(qū)動(dòng)模塊采集的數(shù)據(jù),根據(jù)應(yīng)用場、需求,可以提供多種應(yīng)用服務(wù),例如:數(shù)據(jù)轉(zhuǎn)發(fā)服務(wù)、4-20mA服務(wù)、短信服務(wù)、LED服務(wù)、OPC服務(wù)、以及復(fù)雜的實(shí)時(shí)數(shù)據(jù)分析服務(wù)等。在保障數(shù)據(jù)實(shí)時(shí)性、穩(wěn)定性的前提下,服務(wù)接口可以提供統(tǒng)一的服務(wù)機(jī)制,方便開發(fā)者進(jìn)行二次開發(fā)。
服務(wù)插件的服務(wù)方式,這種服務(wù)是長期運(yùn)行的事務(wù)性任務(wù),所以更復(fù)雜一些。
有些服務(wù)需要隨宿主程序啟動(dòng)而自動(dòng)運(yùn)行,有些服務(wù)需要人工手動(dòng)啟動(dòng)才運(yùn)行。在宿主程序啟動(dòng)的時(shí)候通過配制文件要把服務(wù)的信息加載到菜單上,菜單里顯示的服務(wù)可能有些已經(jīng)啟動(dòng)了;有些需要通過單擊操作,顯示窗體并填寫必要的信息后才可能啟動(dòng)。所以,宿主程序與服務(wù)插件不是單向交互,而是雙向數(shù)據(jù)、事件交互。
IappService服務(wù)接口在IPlugins基礎(chǔ)上進(jìn)行擴(kuò)展,增加了函數(shù)、屬性和事件,代碼定義如下:
public interface IAppService : IPlugins{ /// <summary> /// 啟動(dòng)服務(wù) /// </summary> void StartService(); /// <summary> /// 是否自動(dòng)啟動(dòng) /// </summary> bool IsAutoStart { set; get; } /// <summary> /// 服務(wù)類型 /// </summary> ServiceType ServiceType { set; get; } /// <summary> /// 單擊事件,關(guān)聯(lián)菜單 /// </summary> void OnClick(); /// <summary> /// 釋放服務(wù) /// </summary> void ReleaseService(); /// <summary> /// 寫日志事件 /// </summary> event WriteLogHandler WriteLogHandler;}
(1) StartService函數(shù):當(dāng)服務(wù)的啟動(dòng)方式(IsAutoStart)為"自動(dòng)啟動(dòng)"的時(shí)候,框架平臺(tái)在加載服務(wù)的時(shí)候,會(huì)自動(dòng)調(diào)用這個(gè)接口函數(shù),表示對服務(wù)進(jìn)行啟動(dòng)操作。
(2) IsAutoStart屬性:服務(wù)啟動(dòng)類型,標(biāo)識(shí)是否隨框架平臺(tái)啟動(dòng)而自動(dòng)啟動(dòng),也就是標(biāo)識(shí)是否會(huì)調(diào)用StartService接口函數(shù)。
(3) ServiceType屬性:服務(wù)類型分為:顯示模式和隱藏模式。顯示模式的服務(wù)會(huì)在框架平臺(tái)的菜單上加載以ThisName標(biāo)識(shí)的服務(wù)名稱;隱藏模式不會(huì)在框架平臺(tái)的菜單中加載服務(wù)名稱,可以把此類服務(wù)的IsAutoStart屬性設(shè)置為自動(dòng)啟動(dòng),框架平臺(tái)啟動(dòng)后自動(dòng)啟動(dòng)服務(wù)。代碼定義如下:
public enum ServiceType{ [EnumDescription("顯示模式")] Show = 0x00, [EnumDescription("隱藏模式")] Hide = 0x01}
(4) OnClick事件函數(shù):當(dāng)服務(wù)類型ServiceType為“顯示模式“的時(shí)候,服務(wù)名稱會(huì)被加載到菜單中,當(dāng)單擊服務(wù)菜單項(xiàng)的時(shí)候,會(huì)調(diào)用相應(yīng)服務(wù)的OnClick接口函數(shù),可以在這個(gè)接口函數(shù)里調(diào)用窗體。
(5) ReleaseService函數(shù):當(dāng)關(guān)閉框架平臺(tái)和人工手動(dòng)停止服務(wù)后,可以通過這個(gè)函數(shù)釋放服務(wù)資源。
另外,對于服務(wù)組件接口還涉及到服務(wù)狀態(tài),標(biāo)識(shí)服務(wù)在運(yùn)行的過程中處
于什么階段,例如:服務(wù)正在啟動(dòng)、服務(wù)已經(jīng)啟動(dòng)、服務(wù)正在運(yùn)行、服務(wù)正在終止、服務(wù)已經(jīng)終止等等。因?yàn)楦鶕?jù)服務(wù)的事務(wù)復(fù)雜度不同,服務(wù)的狀態(tài)也可能不同,所以服務(wù)狀態(tài)的定義交給了二次開發(fā)者自己定義。
圖形顯示接口、數(shù)據(jù)導(dǎo)出接口和服務(wù)組件接口都分別有一個(gè)接口管理器,負(fù)責(zé)對各功能接口進(jìn)行管理,它們都繼承自IBaseManager<TKey, TValue>接口。繼承關(guān)系圖如下:
總的來說,框架平臺(tái)涉及到四個(gè)主要的接口:IRunDevice設(shè)備驅(qū)動(dòng)接口、IGraphicsShow圖形顯示接口、IExportData數(shù)據(jù)導(dǎo)出接口和IAppService服務(wù)組件接口。它們現(xiàn)在的繼承結(jié)構(gòu)關(guān)系如下圖:
實(shí)際上繼承這四個(gè)接口二次開發(fā)的模塊都是以插件的形式加載到框架平臺(tái),框架平臺(tái)在結(jié)構(gòu)上實(shí)現(xiàn)了一整套的運(yùn)行機(jī)制。對上面的繼承關(guān)系結(jié)構(gòu)圖進(jìn)行分析,還有整合、重構(gòu)的余地,進(jìn)一步明晰接口關(guān)系、整合代碼,提高框架的可擴(kuò)展性,計(jì)劃重構(gòu)后的接口繼承關(guān)系如下圖:
所有可擴(kuò)展的接口都繼承自一個(gè)插件接口,再分支出來其他的業(yè)務(wù)功能接口,類似于C#語言中所有實(shí)體都繼承自O(shè)bject一樣。
框架內(nèi)部實(shí)際上是對接口進(jìn)行直接調(diào)用,接口與接口之間的配合又實(shí)現(xiàn)了一套協(xié)調(diào)機(jī)制,從而逐步實(shí)現(xiàn)了一個(gè)框架平臺(tái)。作為接口實(shí)際上是實(shí)現(xiàn)了二次開發(fā)與框架平臺(tái)對接的一種形式,并保證在框架平臺(tái)的協(xié)調(diào)機(jī)制中實(shí)現(xiàn)特定的業(yè)務(wù)功能。所以,任何框架,從頂層來看都是對接口的設(shè)計(jì)。
作者:唯笑志在
mail:504547114@QQ.com
QQ:504547114
.NET開發(fā)技術(shù)聯(lián)盟:54256083
文檔下載:http://pan.baidu.com/s/1pJ7lZWf
官方網(wǎng)址:http://www.bmpj.net
新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注