C# 设计模式

  我居然连一月一随笔都没有,啊啊啊,忙死个人

  这个随笔主要是记录基于自己学习[美]James W.Cooper著的《C# Design Patterns : A Tutorial》一书中常用设计模式的整理,既是自己整理的,便避免不了理解偏差,欢迎分享宝贵见解。

Behavioral Pattern  行为型模式

  行为型模式模式主要与对象间的通信有关。

  Chain of Responsibility(职责链模式),职责链模式减少对象间的耦合。整理了一个接口,如下:

 

    /// <summary>
    /// 职责链模式
    /// 职责链减少了类之间的耦合
    /// </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) 职责链模式允许多个类处理同一个请求,请求在类之间传递,直到其中一个类处理它为止。

p) 不想把相互作用的内容放在调用程序里。

举例:

例2:

最近想关于硬件命令和数据收发时想到了用职责链解决,结果好像出现了偏差,便有了以下代码。以下代码用于统计字符串中JMB三个字母出现的次数以及J出现的次数以及两个B字母间用时(实属瞎JB写)。

以下是相关类定义:

  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;   好烦啊,想偷个懒的,意思到就好了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对象优先去处理
            // 如果_prior对象不能处理,自动转交给它的"下一链"处理直到_default
            _prior.OnChain(today);
        }
    }
View Code

  Strategy Pattern(策略模式)

适用:

p) 不同算法各自封装,可随意挑选需要的算法。

实现:

方式一,把策略封装在单独的类中。策略决策类和策略类间的耦合较低(当更换策略时,策略决策类与原策略类解耦);可提供异步获取结果的方法;

方式二,把策略作为一个委托(根据自己理解实现的,自荐)。性能(反射)可能较低;策略决策类与策略(委托,当为其他类中的方法时)所属类间的耦合较高;策略相对轻量级、灵活方便;对于同个问题的策略,可封装在单独类中,结构清晰;

举例:

方式二,具体实现。

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 创建型模式

  所有创建型模式都涉及到创建对象实例的方式。将创建对象过程抽象成一个专门的“创建器”类,会使程序更灵活、更通用。

  Singleton Pattern(单例模式),单例模式限制而不是改进类的创建,单例模式保证一个类有且只有一个实例,并提供一个访问它的全局访问点。如果有需要,也可以在类中保存少数几个实例。我常用单例的全局访问功能;在你只持有一个资源,而需要对外开放多个资源访问服务时,用单例是很好的选择。

举例:

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

        // 应用程序域中第一次发生以下事件时将触发静态构造函数的执行:
        //•    创建类类型的实例。(外部无法创建本类实例)
        //•    引用类类型的任何静态成员。(当Instance属性被引用时)
        static Myself()
        {
            _instance = new Myself();
        }

        private Myself()  // 私有构造限制外部创建实例
        { }
    }

 备注:

此单例的实现是我根据静态构造的特性实现的,以下称前者;书中的单例用lock方式实现,以下称后者。我用循环1000次调用某单例的两种实现的方法(简单返回字符串):第一次调用前者用时0毫秒,后者用时2毫秒,也就是说后者用时是在第一次调用(也就是构造函数花费的)时出现的,以后每次调用二者都是0毫秒;值得一提的点,每个1000次调用中,后者总会至少有一次返回空,也就是调用失败或者啥,但前者不会有这种情况,也就是说前者较为安全。有时间我把测试也贴出来。

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

posted @ 2019-03-01 23:51  不会吉他的程序员  阅读(728)  评论(0编辑  收藏  举报