电竞比分网-中国电竞赛事及体育赛事平台

分享

C# 設(shè)計(jì)模式

 路人甲Java 2020-07-14

  我居然連一月一隨筆都沒有,啊啊啊,忙死個(gè)人

  這個(gè)隨筆主要是記錄基于自己學(xué)習(xí)[美]James W.Cooper著的《C# Design Patterns : A Tutorial》一書中常用設(shè)計(jì)模式的整理,既是自己整理的,便避免不了理解偏差,歡迎分享寶貴見解。

Behavioral Pattern  行為型模式

  行為型模式模式主要與對象間的通信有關(guān)。

  Chain of Responsibility(職責(zé)鏈模式),職責(zé)鏈模式減少對象間的耦合。整理了一個(gè)接口,如下:

 

    /// <summary>
    /// 職責(zé)鏈模式
    /// 職責(zé)鏈減少了類之間的耦合
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public interface IChain<T>
    {
        /// <summary>
        /// 添加一條鏈至本鏈后
        /// </summary>
        /// <param name="nextChain"></param>
        void AddNext(IChain<T> nextChain);

        /// <summary>
        /// 消息處理
        /// </summary>
        /// <param name="msg"></param>
        void OnChain(T msg);
    }

 

適用:

p) 職責(zé)鏈模式允許多個(gè)類處理同一個(gè)請求,請求在類之間傳遞,直到其中一個(gè)類處理它為止。

p) 不想把相互作用的內(nèi)容放在調(diào)用程序里。

舉例:

例2:

最近想關(guān)于硬件命令和數(shù)據(jù)收發(fā)時(shí)想到了用職責(zé)鏈解決,結(jié)果好像出現(xiàn)了偏差,便有了以下代碼。以下代碼用于統(tǒng)計(jì)字符串中JMB三個(gè)字母出現(xiàn)的次數(shù)以及J出現(xiàn)的次數(shù)以及兩個(gè)B字母間用時(shí)(實(shí)屬瞎JB寫)。

以下是相關(guān)類定義:

  1 using System;
  2 using System.Collections.Generic;
  3 
  4 namespace ConcurrencySolution
  5 {
  6     #region base classes
  7     public class Msg
  8     {
  9         public string ID
 10         {
 11             get { return _id; }
 12         }
 13         private string _id;
 14 
 15         public Msg()
 16         {
 17             _id = Guid.NewGuid().ToString("N");
 18         }
 19     }
 20 
 21     public class MsgRep
 22     {
 23         public string MsgID;
 24 
 25         public bool ExecResult;
 26 
 27         public MsgRep()
 28             : this(string.Empty, false)
 29         { }
 30 
 31         public MsgRep(string vMsgID, bool vExecResult)
 32         {
 33             MsgID = vMsgID;
 34             ExecResult = vExecResult;
 35         }
 36     }
 37 
 38     public abstract class Chain
 39     {
 40         public Chain Next
 41         {
 42             get { return _next; }
 43         }
 44         private Chain _next;
 45 
 46         public void SetNext(Chain next)
 47         {
 48             _next = next;
 49         }
 50 
 51         public MsgRep HandleMsg(Msg msg)
 52         {
 53             MsgRep rep = HandleMessage(msg);
 54             if (true == rep.ExecResult)
 55                 return rep;
 56 
 57             if (Next != null)
 58                 return Next.HandleMsg(msg);
 59 
 60             return null;
 61         }
 62 
 63         protected abstract MsgRep HandleMessage(Msg msg);
 64     }
 65 
 66     public abstract class Worker : Chain
 67     {
 68         public string WorkerID
 69         {
 70             get { return _workerID; }
 71         }
 72         protected string _workerID;
 73 
 74         protected Worker()
 75             : this(string.Empty)
 76         { }
 77 
 78         protected Worker(string vWorkerID)
 79         {
 80             _workerID = vWorkerID;
 81         }
 82 
 83         protected override MsgRep HandleMessage(Msg msg)
 84         {
 85             WorkerMsg wmsg = msg as WorkerMsg;
 86             if (null == wmsg)
 87                 throw new ArgumentException("isn't a valid WorkerMsg", "msg");
 88 
 89             var rep = DoWork(wmsg);
 90             return rep;
 91         }
 92 
 93         protected abstract WorkerMsgRep DoWork(WorkerMsg msg);
 94     }
 95     #endregion
 96 
 97     public class WorkerMsg : Msg
 98     {
 99         public string Action
100         {
101             get { return _action; }
102         }
103         private string _action;
104 
105         public WorkerMsg(string vAction)
106             : base()
107         {
108             _action = vAction;
109         }
110     }
111 
112     public class WorkerMsgRep : MsgRep
113     {
114         public string WorkerID;
115 
116         public WorkerMsgRep()
117             : this(string.Empty, false, string.Empty)
118         { }
119 
120         public WorkerMsgRep(string vMsgID, bool vExecResult, string vWorkerID)
121             : base(vMsgID, vExecResult)
122         {
123             WorkerID = vWorkerID;
124         }
125     }
126 
127     #region Workers
128     public class WorkerJ : Worker
129     {
130         public int MentionTimes
131         {
132             get { return _mentionTimes; }
133         }
134         protected int _mentionTimes;
135 
136         protected WorkerJ()
137             : base()
138         { }
139 
140         public WorkerJ(string vWorkerID)
141             : base(vWorkerID)
142         { }
143 
144         protected override WorkerMsgRep DoWork(WorkerMsg msg)
145         {
146             WorkerMsgRep rep = new WorkerMsgRep(msg.ID, false, WorkerID);
147             rep.ExecResult = msg.Action == "J";
148             if (true == rep.ExecResult)
149                 _mentionTimes++;
150 
151             return rep;
152         }
153 
154         public virtual void ChangeWorkerID(string vWorkerID)
155         {
156             throw new NotImplementedException();
157         }
158     }
159 
160     public class WorkerM : Worker
161     {
162         public WorkerM(string vWorkerID)
163             : base(vWorkerID)
164         { }
165 
166         protected override WorkerMsgRep DoWork(WorkerMsg msg)
167         {
168             var rep = new WorkerMsgRep(msg.ID, false, WorkerID);
169             if (msg.Action == "M")
170                 rep.ExecResult = true;
171 
172             return rep;
173         }
174     }
175 
176     public class WorkerB : Worker
177     {
178         public List<DateTime> MentionTime
179         {
180             get { return _mentionTime; }
181         }
182         List<DateTime> _mentionTime;
183 
184         public WorkerB(string vWorkerID)
185             : base(vWorkerID)
186         {
187             _mentionTime = new List<DateTime>();
188         }
189 
190         protected override WorkerMsgRep DoWork(WorkerMsg msg)
191         {
192             WorkerMsgRep rep = new WorkerMsgRep(msg.ID, false, WorkerID);
193             rep.ExecResult = msg.Action == "B";
194             if (true == rep.ExecResult)
195                 _mentionTime.Add(DateTime.Now);
196 
197             return rep;
198         }
199 
200 
201     }
202     #endregion
203 }
View Code

以下是使用:

        public void TestMethod1()
        {
            string testStr = "Bb1123lkiJMoBp";
            WorkerJ wj = new WorkerJ("j");
            WorkerM wm = new WorkerM("m");
            WorkerB wb = new WorkerB("B");
            wj.SetNext(wm);
            wm.SetNext(wb);

            int countJMB = 0;
            WorkerMsg ms;
            WorkerMsgRep mr;
            for (int i = 0; i < testStr.Length; i++)
            {
                ms = new WorkerMsg(testStr[i].ToString());
                mr = wj.HandleMsg(ms) as WorkerMsgRep;
                if (mr != null &&
                    true == mr.ExecResult)
                    countJMB++;
            }

            string time1 = wb.MentionTime[0].ToString("HH:mm:ss:ms");
            string time2 = wb.MentionTime[1].ToString("HH:mm:ss:ms");
            ;
        }
View Code

例1:

    public class Sunday : IChain<DayOfWeek>  // System.DayOfWeek
    {
        private IChain<DayOfWeek> _next;

        private DayOfWeek _token;
        public DayOfWeek Token { get { return _token; } }

        public Sunday()
        {
            _token = DayOfWeek.Sunday;
        }

        #region  IChain<DayOfWeek> 成員
        void IChain<DayOfWeek>.AddNext(IChain<DayOfWeek> nextChain)
        {
            _next = nextChain;
        }

        void IChain<DayOfWeek>.OnChain(DayOfWeek msg)
        {
            if (DayOfWeek.Sunday == msg)  // 此處判斷本類是否最適合處理此消息
            {
                Console.WriteLine("Hello! It's {0}, u'd better study!", _token);
            }
            else if (_next != null)  // 傳遞消息
            {
                _next.OnChain(msg);
            }
            else
            {
                throw new Exception(string.Format("{0} can't handle this msg : {1}", _token, msg));
            }
        }
        #endregion

    }

    public class DefaultDay : IChain<DayOfWeek>
    {
        private DayOfWeek _token;
        public DayOfWeek Token { get { return _token; } }

        public DefaultDay()
        {
            //_token = DayOfWeek.None;   好煩啊,想偷個(gè)懶的,意思到就好了8
        }

        #region  IChain<DayOfWeek> 成員
        void IChain<DayOfWeek>.AddNext(IChain<DayOfWeek> nextChain)
        {
            throw new NotImplementedException(string.Format("Sorry but i'm at the end of the chain, {0} said.", _token));
        }

        void IChain<DayOfWeek>.OnChain(DayOfWeek msg)
        {
            //if (msg != _token)
            //{
            //    throw new Exception(string.Format("It's none of my business about : {0}, {1} said", msg, _token));
            //}
            //else
            //{
                Console.WriteLine("Unbelievable! Today is {0}!", _token);
            //}

        }
        #endregion

    }

    public class ChainImpl
    {
        IChain<DayOfWeek> _prior, _inferior, _default;

        public ChainImpl()
        {
            _prior = new Sunday();
            //_inferior = new Monday();
            _default = new DefaultDay();

            //_prior.AddNext(_inferior);
            //_inferior.AddNext(_default);
            _prior.AddNext(_default);
        }

        public void Work(DayOfWeek today)
        {  
            // 不管今天具體是周幾,由_prior對象優(yōu)先去處理
            // 如果_prior對象不能處理,自動轉(zhuǎn)交給它的"下一鏈"處理直到_default
            _prior.OnChain(today);
        }
    }
View Code

  Strategy Pattern(策略模式)。

適用:

p) 不同算法各自封裝,可隨意挑選需要的算法。

實(shí)現(xiàn):

方式一,把策略封裝在單獨(dú)的類中。策略決策類和策略類間的耦合較低(當(dāng)更換策略時(shí),策略決策類與原策略類解耦);可提供異步獲取結(jié)果的方法;

方式二,把策略作為一個(gè)委托(根據(jù)自己理解實(shí)現(xiàn)的,自薦)。性能(反射)可能較低;策略決策類與策略(委托,當(dāng)為其他類中的方法時(shí))所屬類間的耦合較高;策略相對輕量級、靈活方便;對于同個(gè)問題的策略,可封裝在單獨(dú)類中,結(jié)構(gòu)清晰;

舉例:

方式二,具體實(shí)現(xiàn)。

using System;

    public class StrategyDecision
    {
        protected Delegate _strategy;

        public StrategyDecision()
        { }

        public StrategyDecision(Delegate strategy)
        {
            _strategy = strategy;
        }

        ~StrategyDecision()
        {
            _strategy = null;
        }

        public object GetResult(params object[] args)
        {
            try
            {
                return _strategy.DynamicInvoke(args);
            }
            catch (Exception e)
            {
                throw e;
            }
        }

        public void ChangeStrategy(Delegate strategy)
        {
            _strategy = strategy;
        }

    }
View Code

方式二,使用舉例。

var obj = new StrategyDecision(
                            new Func<int, int, int>(
                                (oa, ob) =>
                                {
                                    return oa + ob;

                                })).GetResult(7, 7);  // Bad example! 圖簡便 >_<

Creational Pattern 創(chuàng)建型模式

  所有創(chuàng)建型模式都涉及到創(chuàng)建對象實(shí)例的方式。將創(chuàng)建對象過程抽象成一個(gè)專門的“創(chuàng)建器”類,會使程序更靈活、更通用。

  Singleton Pattern(單例模式),單例模式限制而不是改進(jìn)類的創(chuàng)建,單例模式保證一個(gè)類有且只有一個(gè)實(shí)例,并提供一個(gè)訪問它的全局訪問點(diǎn)。如果有需要,也可以在類中保存少數(shù)幾個(gè)實(shí)例。我常用單例的全局訪問功能;在你只持有一個(gè)資源,而需要對外開放多個(gè)資源訪問服務(wù)時(shí),用單例是很好的選擇。

舉例:

    public class Myself
    {
        static readonly Myself _instance;
        public static Myself Instance
        {
            get { return _instance; }
        }

        // 應(yīng)用程序域中第一次發(fā)生以下事件時(shí)將觸發(fā)靜態(tài)構(gòu)造函數(shù)的執(zhí)行:
        //•    創(chuàng)建類類型的實(shí)例。(外部無法創(chuàng)建本類實(shí)例)
        //•    引用類類型的任何靜態(tài)成員。(當(dāng)Instance屬性被引用時(shí))
        static Myself()
        {
            _instance = new Myself();
        }

        private Myself()  // 私有構(gòu)造限制外部創(chuàng)建實(shí)例
        { }
    }

 備注:

此單例的實(shí)現(xiàn)是我根據(jù)靜態(tài)構(gòu)造的特性實(shí)現(xiàn)的,以下稱前者;書中的單例用lock方式實(shí)現(xiàn),以下稱后者。我用循環(huán)1000次調(diào)用某單例的兩種實(shí)現(xiàn)的方法(簡單返回字符串):第一次調(diào)用前者用時(shí)0毫秒,后者用時(shí)2毫秒,也就是說后者用時(shí)是在第一次調(diào)用(也就是構(gòu)造函數(shù)花費(fèi)的)時(shí)出現(xiàn)的,以后每次調(diào)用二者都是0毫秒;值得一提的點(diǎn),每個(gè)1000次調(diào)用中,后者總會至少有一次返回空,也就是調(diào)用失敗或者啥,但前者不會有這種情況,也就是說前者較為安全。有時(shí)間我把測試也貼出來。

  Linkin Park 的《Halfway Right》好聽哭了T_T,一定要聽!

    本站是提供個(gè)人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多