消息模式在實際開發應用中的優點

曾經.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 消息集中處理控制更加靈活。

相關文章
相關標籤/搜索