曾经.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 消息集中处理控制更加灵活。