zoukankan      html  css  js  c++  java
  • 消息模式

    消息模式

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

     
     
  • 相关阅读:
    cf359D Pair of Numbers
    cf671B Robin Hood
    [暑假集训--数位dp]hdu5787 K-wolf Number
    [暑假集训--数位dp]UESTC250 windy数
    [暑假集训--数位dp]LightOj1205 Palindromic Numbers
    [暑假集训--数位dp]LightOJ1140 How Many Zeroes?
    [暑假集训--数位dp]LightOj1032 Fast Bit Calculations
    [暑假集训--数位dp]hdu5898 odd-even number
    [暑假集训--数位dp]cf55D Beautiful numbers
    [暑假集训--数位dp]hdu3709 Balanced Number
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/5782408.html
Copyright © 2011-2022 走看看