曾經.NET面試過程當中常常問的一個問題是,若是程序集A,引用B ,B 引用C,那麼C怎麼去訪問A中的方法呢。html
這個問題初學.net可能一時想不出該咋處理,這涉及到循環引用問題。但有點經驗的可能就簡單了,經過委託的方式,從A中傳遞到C中,而後在C中就能夠訪問了。還有經過接口方式也能夠。面試
可是若是項目中有很是多的程序集, A B C D E F G 並且互相都有交叉的訪問關係,任何二者都有可能訪問,那麼若是用接口和委託可能就不是那麼方便了。算法
消息模式不單單能夠完美解決上述問題,還可使得全部交互都集中處理,使用更方便。this
最近開發的一個系統,涉及到諸多數據處理以及控制層,並且之間大都存在循環訪問的問題,若是不用消息模式,系統將變得很是難於維護。spa
系統有以下幾層:UI層,指令層,數據層,算法層,狀態層。 .net
UI層須要通知指令層參數變動等。指令層須要通知UI層,發出買入賣出操做而且更改UI顯示。設計
狀態層狀態改變後,須要通知UI層顯示變動,指令層訪問算法層,指令層執行算法發現知足條件時,通知狀態層變動。狀態層狀態變動後,通知指令層狀態變動正常或者異常。而後進一步後續操做code
還有自定義控件須要訪問Form中的方法以及給form發送通知都是經過發送消息的方式來實現的。orm
項目結構以及數據控制流圖以下(數據控制流只標記了部分,實際流更多)htm
消息中心 主要包括兩個靜態方法,一個公共事件,這裏負責系統中全部的事件訂閱以及事件觸發的樞紐
namespace Common { /// <summary> /// 消息事件參數 /// </summary> public class MessageArg : EventArgs { /// <summary> /// 消息類型 /// </summary> public EnumMsgtype mstType { set; get; } public string gpCode { set; get; } public string message { set; get; } /// <summary> /// 擴展數據 /// </summary> public object ExtendData { set; get; } } public class MessageCenter { public static MessageCenter Instanse = null; static MessageCenter() { Instanse = new MessageCenter(); } public delegate void MessageHandle(Object sender, MessageArg e); /// <summary> /// 消息事件 /// </summary> public event MessageHandle OnMessage; /// <summary> /// 發送事件(後續添加的,發現消息模式的諸多便利) /// </summary> /// <param name="gpCode"></param> /// <param name="eventType"></param> /// <param name="extendData"></param> public static void SendEvent(string gpCode,EnumMsgtype eventType, object extendData) { if(MessageCenter.Instanse.OnMessage!=null) { try { MessageCenter.Instanse.OnMessage(MessageCenter.Instanse, new MessageArg() { mstType = eventType, gpCode = gpCode, ExtendData = extendData }); } catch(Exception ex) { ShowExceptionMsg(ex, gpCode); } } } /// <summary> /// 提示信息(一開始設計僅僅是想發送消息) /// </summary> /// <param name="mstType"></param> /// <param name="gpCode"></param> /// <param name="message"></param> public static void ShowMessage(EnumMsgtype mstType, string gpCode, string message) { if (MessageCenter.Instanse.OnMessage != null) { MessageCenter.Instanse.OnMessage(MessageCenter.Instanse, new MessageArg() { mstType = mstType, gpCode = gpCode, message = message }); } } /// <summary> /// 發送異常信息 /// </summary> /// <param name="ex"></param> /// <param name="gpCode"></param> public static void ShowExceptionMsg(Exception ex, string gpCode) { EnumMsgtype msgType; string msg = ""; if (ex is ApplicationException) { msgType = EnumMsgtype.ImportantInfo; msg = ex.Message; } else { msgType = EnumMsgtype.SysError; msg = ex.ToString(); } ShowMessage(msgType, gpCode, msg); } } }
指令中心 發送通知舉例
MessageCenter.SendEvent(singleStatus.GpCode, EnumMsgtype.ManageBeforeChangeEvent, singleStatus);//觸發操做前事件
MessageCenter.SendEvent(singleStatus.GpCode, EnumMsgtype.ManageChangeEvent, singleStatus);//觸發操做後事件
private void SetGpBuy(PriceTimeModel gpRealTimeData, GpStatusManage gpStatus) { //全部須要買的狀態項 List<GpStatusBase> lstBuyStatus = gpStatus.AllNeedBuyStatus; //依次進行驗證操做 foreach (var singleStatus in lstBuyStatus) { //設置狀態的最後一個股票信息 singleStatus.LasterOpraPriceItem = gpRealTimeData; //獲取股票算法 ManageRuleBase saleRule = ManageRuleBase.GetRule(gpStatus.GpParameterItem.LogicType); saleRule.PriceChange(gpRealTimeData, singleStatus); bool isCanBuy = CheckCanBuy(gpRealTimeData, singleStatus, saleRule); if (isCanBuy) { MessageCenter.SendEvent(singleStatus.GpCode, EnumMsgtype.ManageBeforeChangeEvent, singleStatus); //緊急暫停 if (IsStopBuy || singleStatus.GpItem.IsStopBuy) { MessageCenter.ShowMessage(EnumMsgtype.StatusInfo, singleStatus.GpCode, gpRealTimeData.GetGpcodeAndTimeStr() + singleStatus.ManageTypeName + "緊急暫停,取消買操做"); continue; } //的判斷是上面這個事件可能會更改狀態 if (singleStatus.CanManage == false || singleStatus.ManageCnt==0) { MessageCenter.ShowMessage(EnumMsgtype.StatusInfo, singleStatus.GpCode, gpRealTimeData.GetGpcodeAndTimeStr() + singleStatus.ManageTypeName + "數量不足,取消買操做"); continue; } //發出買指令(鎖訂價格買) var para = new ManageParameter() { GpCode = singleStatus.GpItem.GpCode, InstructWay = EnumInstruct.Buy, ManagePrice = singleStatus.LockPrice + gpStatus.GpItem.ChangePersontToPrice(0.2f),//加上0.3百分點增長買入成功率 //0322仍是更改鎖訂價格+0.2f ManageCnt = singleStatus.ManageCnt, PriceItem = gpRealTimeData, GpItem = singleStatus.GpItem }; //外掛操做 if (waiguaOprationer.GpManage(para)) { float managePrice = gpRealTimeData.Price + gpStatus.GpItem.ChangePersontToPrice(0.2f); singleStatus.ManagePrice = float.Parse(managePrice.ToString("f2")); singleStatus.ManagePriceItem = gpRealTimeData; //買入,更改狀態 singleStatus.SetGpStatusAfterEvent(EnumOprationStatus.Buyed); lstNeedCheckStatus.Add(singleStatus); //通知 MessageCenter.ShowMessage(EnumMsgtype.StatusInfo, gpStatus.GpCode , gpRealTimeData.GetGpcodeAndTimeStr() + singleStatus.ManageTypeName+ "買入操做成功,待驗證\r\n"); //操做變動事件 MessageCenter.SendEvent(singleStatus.GpCode, EnumMsgtype.ManageChangeEvent, singleStatus); } } } }
UI接收消息舉例
訂閱消息 MessageCenter.Instanse.OnMessage += Instanse_OnMessage;
對不一樣的消息類型分別處理
private void Instanse_OnMessage(object sender, MessageArg e) { try { if (GpItem != null && e.gpCode == "") { //清空 if (e.mstType == EnumMsgtype.ClearDataEvent) { this.lstOnePara.ForEach(t => { t.SingleStatus = null; t.ReinitStepStyle(); }); } } if (GpItem != null && e.gpCode == GpItem.GpCode) { //若是不在Form控制下,那麼取消事件註冊!!! var parFrm = FindParentForm(); if (parFrm == null) { //這裏一般是因爲導入了參數,致使的額外註冊 MessageCenter.Instanse.OnMessage -= Instanse_OnMessage; return; } if (e.mstType == EnumMsgtype.PriceChangeEvent) { // } //消息 else if (e.mstType == EnumMsgtype.Info || e.mstType == EnumMsgtype.ImportantInfo || e.mstType == EnumMsgtype.StatusInfo) { // } else if (e.mstType == EnumMsgtype.ManageBeforeChangeEvent)//操做以前事件 { // } else if (e.mstType == EnumMsgtype.ManageChangeEvent)//操做以後事件 { // } else if (e.mstType == EnumMsgtype.AutoLockChangeEvent)//智能鎖定 { // } else if(e.mstType== EnumMsgtype.MonitStartEvent) { // } } } catch(Exception ex) { MessageCenter.ShowExceptionMsg(ex, GpItem.GpCode); } }
文中的舉例的軟件以及下載地址在我另一博文中介紹
http://www.cnblogs.com/blackvis/p/5779443.html
總結消息模式的幾大優勢
1 解決程序集循環訪問的問題
2 程序集解耦,對於少許通訊的程序集之間不須要存在引用關係,就可達到互相通信,亦可減小程序集中的public方法數量。
3 消息以廣播的形式進行發送,使得一處發送,多處重複使用。
4 消息集中處理控制更加靈活。