|
我居然連一月一隨筆都沒有,啊啊啊,忙死個(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 } 以下是使用:
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"); ; } 例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); } } 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; } } 方式二,使用舉例。 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,一定要聽! |
|
|