曾经. NET 面试过程中经常问的一个问题是,如果程序集 A,引用 B ,B 引用 C,那么 C 怎么去访问 A 中的方法呢。
这个问题初学. net 可能一时想不出该咋处理,这涉及到循环引用问题。但有点经验的可能就简单了,通过委托的方式,从 A 中传递到 C 中,然后在 C 中就可以访问了。还有通过接口方式也可以。
但是如果项目中有非常多的程序集, A B C D E F G 而且互相都有交叉的访问关系,任何两者都有可能访问,那么如果用接口和委托可能就不是那么方便了。
消息模式不仅仅可以完美解决上述问题,还可以使得所有交互都集中处理,使用更方便。
最近开发的一个系统,涉及到诸多数据处理以及控制层,而且之间大都存在循环访问的问题,如果不用消息模式,系统将变得非常难于维护。
系统有如下几层:UI 层,指令层,数据层,算法层,状态层。
UI 层需要通知指令层参数变更等。指令层需要通知 UI 层,发出买入卖出操作并且更改 UI 显示。
状态层状态改变后,需要通知 UI 层显示变更,指令层访问算法层,指令层执行算法发现满足条件时,通知状态层变更。状态层状态变更后,通知指令层状态变更正常或者异常。然后进一步后续操作
还有自定义控件需要访问 Form 中的方法以及给 form 发送通知都是通过发送消息的方式来实现的。
项目结构以及数据控制流图如下(数据控制流只标记了部分,实际流更多)
消息中心 主要包括两个静态方法,一个公共事件,这里负责系统中所有的事件订阅以及事件触发的枢纽
- 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 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 消息集中处理控制更加灵活。
来源: http://www.cnblogs.com/blackvis/p/5782288.html