消息模式

消息模式

曾经.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<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+ "买入操作成功,待验证
");
                        //操作变更事件
                        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 消息集中处理控制更加灵活。

 
 
原文地址:https://www.cnblogs.com/Leo_wl/p/5782408.html