1. 引言
一個專案的通常都是從Demo開始,不斷為專案新增新的功能以及重構,也許剛開始的時候程式碼顯得非常凌亂,毫無設計可言。但是隨著專案的迭代,往往需要將很多相同功能的程式碼抽取出來,這也是設計模式的開始。熟練運用設計模式應該是每一個軟體開發人員的必備技能。今天給大家介紹幾個常用的設計模式。
2. 單例模式
單例模式恐怕是很多開發人員最先接觸到的模式之一,可以認為就是一個全域性變數。它的初始化過程無非就是一開始就new 一個instance,或者惰性初始化等需要用到的時候new 一個instance。這裡需要注意的是在多執行緒情況下new一個instance。通常加上lock 可以解決問題。這裡我們利用C# 的系統函式 Interlocked.CompareExchange
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
internal class SingletonOne { private static SingletonOne _singleton; private SingletonOne() { } public static SingletonOne Instance { get { if (_singleton == null) { Interlocked.CompareExchange(ref _singleton, new SingletonOne(), null); } return _singleton; } } } |
3. 迭代器模式
迭代器模式也是用的比較多的一種,通常見於C#的內建容器資料結構 List,Stack等等,為了便於遍歷容器內元素。這裡給出一個簡單版的Stack實現
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 |
internal class Stack : IEnumerable, IEnumerable { private T[] _array; private int _index; private const int DefaultSize = 4; public Stack(int size) { var sized = size > 0 ? size : DefaultSize; this._array = new T[sized]; this._index = 0; } public int Count { get { return this._index; } } public Stack(IEnumerable data) : this(0) { var enumrator = data.GetEnumerator(); while (enumrator.MoveNext()) { var item = enumrator.Current; this.Push(item); } } public void Push(T item) { if (this._index this._array.Length) { this._array[this._index++] = item; } else { var newLength = this._array.Length 1; T[] newArray = new T[newLength]; Array.Copy(this._array, newArray, this.Count); this._array = newArray; this.Push(item); } } public T Pop() { if (this.Count 0) { throw new ArgumentOutOfRangeException("pop"); } else { this._array[this._index] = default(T); return this._array[--this._index]; } } public T Get(int index) { if (this.Count index) { throw new ArgumentOutOfRangeException("Get"); } else { return this._array[index]; } } IEnumerator IEnumerable.GetEnumerator() { return this.GetEnumerator(); } public IEnumerator GetEnumerator() { return new StackEnumerator(this); } } |
Stack 的 迭代器內部實現:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
internal class StackEnumerator : IEnumerator , IEnumerator { private Stack _stack; private int _index; public StackEnumerator(Stack stack) { this._stack = stack; this._index = -1; } public bool MoveNext() { this._index++; return this._index this._stack.Count; } public void Reset() { this._index = -1; } object IEnumerator.Current { get { return this.Current; } } public T Current { get { return this._stack.Get(this._index); } } public void Dispose() { this._stack = null; } } |
4 工廠模式
工廠模式細分的話有簡單工廠模式、抽象工廠模式等。它最核心的就是如何通過 Factory new 一個 物件出來。在ASP.NET MVC 訊息處理實現過程中工廠模式運用的非常多。比如
在MVC中處理一個Request,其實就是呼叫Controller下的一個Action,這就需要從Url 和Route 中反射出Controller物件,內部由ControllerFactory建立。
它的預設實現是:DefaultControllerFactory
另一個例子是ValueProviderFactory,它使得Controller 下的Action 能夠接收到前端傳回來的資料並實現模型繫結,是典型的抽象工廠實現。
5. 訂閱模式
訂閱模式在某些專案運用比較多,比如 Knockout 整個專案就是一個大的訂閱模式的實現,但是它是用javascript編寫的。還有像微博、微信公眾號等等訂閱模式通常少不了。
通常可以定義介面:
1 2 3 4 5 6 7 8 9 10 11 12 |
internal interface ISubject { IEnumerable Observers { get; } void Notify(); void AddObserver(IObserver observer); void RemoveObserver(IObserver observer); } internal interface IObserver { void ReceiveSubject(ISubject subject); } |
實現:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
internal class AritcleObserver : IObserver { public void ReceiveSubject(ISubject subject) { // receive the subject } } class WeChatArticle : ISubject { private ICollection _observers; private string _name; public WeChatArticle(string name) { this._name = name; this._observers = new List(); } public IEnumerable Observers { get { return this._observers; } } public void Notify() { foreach (IObserver observer in this._observers) { observer.ReceiveSubject(this); } } public void AddObserver(IObserver observer) { this._observers.Add(observer); } public void RemoveObserver(IObserver observer) { this._observers.Remove(observer); } } |
6. 責任鏈模式
責任鏈模式沒有像工廠模式那樣被人熟悉,在ASP.NET WebApi 中有一個非常典型的實現 就是WebApi的訊息處理管道HttpMessageHandler
這裡給一個簡單的模擬
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
class DataRequest { public string FileName { get; set; } } class DataResponse { public string Error { get; set; } public string Data { get; set; } } internal abstract class RequestHandler { public RequestHandler NextHandler { get; set; } public abstract DataResponse Process(DataRequest request); } class ReadRequestHandler : RequestHandler { public override DataResponse Process(DataRequest request) { return new DataResponse() { Data = File.ReadAllText(request.FileName) }; } } class ExistsRequestHandler : RequestHandler { public override DataResponse Process(DataRequest request) { if (File.Exists(request.FileName)) { return this.NextHandler.Process(request); } else { return new DataResponse() { Error = "no exists" }; } } } |
7. 組合模式
組合模式是使得單個物件和組合物件有一致的行為,一致的行為可以理解為擁有同一個介面,比如圖形顯示
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
class ControlContext { } internal interface IControl { void Draw(ControlContext context); } class Line : IControl { public void Draw(ControlContext context) { } } class Circle : IControl { public void Draw(ControlContext context) {} } class CompositeControl : IControl { private List controls; public CompositeControl(IList cons) { this.controls = new List(cons); } public void Draw(ControlContext context) { this.controls.ForEach(c => c.Draw(context)); } public void Add(IControl control) { this.controls.Add(control); } } |
8. 總結
市場上有很多關於設計模式的書,但是基本的設計模式大概有20多種,本文給大家介紹了幾種專案中常見的設計模式,其實有些設計模式在實際專案已經不知不覺用起來了。
以後再給大家介紹其他的幾種設計模式。