需求場景還原
國內某二線城市某科技公司,項目、產品繁多,軟硬件通吃。硬件大牛H,軟件新人S,研發BOSS:
H:BOSS,這兩天剛剛搞出個采集電參數的模塊,能不能安排人做個簡單的測試程序,就是一個串口,電腦上看一下數據就行,很簡單的;
BOSS:可以,小S,你把老H這個功能實現下,在我原來的那個XXX串口程序基礎上改一下就行了;
S:我在整個網站,沒時間呀?
BOSS:這個簡單,改一下顯示就行了;
S:行,聽你的(無奈!!)
然后S把BOSS原來的程序COPY一份,開改打開串口--->收數據---->分析數據--->顯示--->關閉串口,丫的還要改程序名字等等
...
X月過后:
H:BOSS,我整了個XX控制器,需要用電腦軟件控制一下就行,就發兩個控制指令,然后看到控制結果就行,很簡單的;
BOSS:老H,你干的不錯呀,小S,你有空把這個控制實現一下,就在你上次那個采集程序基礎上改一下就行了;
S:我上次那網站還沒整完呀?客戶吹的緊呀?
BOSS:這個簡單,就兩個控制指令,算你半天工作量
S:(內心:簡單?簡單$%$$####%^)
然后S把原來的采集程序COPY一份,開改打開串口--->發控制指令--->收數據---->分析數據--->顯示--->關閉串口,丫的還要改程序名字等等
...
又是X月過后:
H:BOSS呀,有個客戶那邊說我們的協議不好使,要用國標的協議,能不能把協議稍微改一下,很簡單的;
BOSS:嗯,客戶第一嘛,小S,耶...小S...小S...小S...小S...
S:老大,我是真沒空呀,讓老H自己改吧,很簡單的,把XX工程打開,改XX文件XX行
H:......
思維的逆轉
搞硬件的老H能改?他知道顯示界面怎么委托?開玩笑,他可能都不知道什么是類;
還有為什么老是拿以前的程序來改?因為我們需要以前的串口讀寫程序,新寫的話太費時間,你說我可以封裝好點,讓別人調用方便點,那還是得調用呀,如果換成網絡TCP怎么辦?再換成其他的怎么辦?
我們對底層依賴的太嚴重了!我們應該把這種依賴倒置(小S:不就是依賴倒置嘛,切!!BOSS:#@¥%,理論害死人呀,你丫知道你不實踐)。我們要做一個平台,無論什么協議,無論什么串口、網絡,甚至其它通信方式,還有WINFORM界面顯示我都把它預先處理好,讓只會簡單C語言的老H只關心他知道的協議; 於是就出現下面這個框架:
綠色表示原始數據包的流向情況,平台自己處理所有與硬件通信功能,所有的協議放在模塊中用戶自己處理。
平台完成開發后,提供一個接口定義的模塊,比如下面這個接口:
namespace IDataMonitor { public abstract class DllBase { /// <summary> /// 接收數據處理函數 /// </summary> /// <param name="buffer">收到的原始數據</param> /// <returns>返回一個字符串,用於采集平台界面顯示</returns> public abstract string OnReceive(byte[] buffer); /// <summary> /// 模塊加載的時候執行,禁止在該函數里編寫長時間執行的代碼,如果需要可以用線程代替 /// </summary> public abstract void DllLoad(); /// <summary> /// 在主程序退出時執行 /// </summary> public abstract void DllUnload(); /// <summary> /// 可以通過該委托發送查詢/控制指令 /// </summary> public Func<byte[], bool> SendFunc; } }
公司內部或其他公司開發人員拿到接口定義模塊后,就可以基於它開發完成自己的協議模塊(DLL形式),然后放置在平台指定的文件夾下即可,無需再次修改數據通信平台的代碼,真正實現公司數據采集平台的通用。
用戶使用
平台搭建完成后,老H只需要新建一個類庫工程,添加接口文件的引用,然后如下處理自己的協議即可:
namespace TestDll { public class Class1 : DllBase { private volatile bool _bListen = true; public override string OnReceive(byte[] buffer) { //這里測試,原包返回 return Encoding.Default.GetString(buffer); } public override void DllLoad() { var thread = new Thread(Query); thread.Start(); } public override void DllUnload() { _bListen = false; } public void Query() { while (_bListen) { string test = "this datas come from test dll"; SendFunc(Encoding.Default.GetBytes(test)); Thread.Sleep(1000); } } } }
然后老H把生成的DLL文件放置在平台運行文件夾下,簡單配置一下對應的具體網絡(或串口):
我為了方便,把測試的串口和網絡都對應到TestDll處理了,運行的效果如下:
通過代碼可以看出,無需了解任何winform、TCP或串口編程知識,甚至可以不用知道什么是TCP,什么是串口,只需要把收到的數據解析出來就行了。小S淚流滿面,BOSS清靜了!!
鏈接
平台主文件DataMonitor工程及相關的接口測試:https://datamonitor.codeplex.com/