在上一篇文章里我通過具體場景總結了“.net面向對象的設計原則”,其中也多次提到一些設計模式方面的技術,可想而知,設計模式在我們的開發過程中也是必不可少的。今天我們就來簡單交流下設計模式。對於設計模式的介紹呢,網上流行這麼一句話“想要搞好對象,必須要熟知套路”,所以百度中說設計模式簡介時“設計模式一 ...
在上一篇文章里我通過具體場景總結了“.net面向對象的設計原則”,其中也多次提到一些設計模式方面的技術,可想而知,設計模式在我們的開發過程中也是必不可少的。今天我們就來簡單交流下設計模式。對於設計模式的介紹呢,網上流行這麼一句話“想要搞好對象,必須要熟知套路”,所以百度中說設計模式簡介時“設計模式一套被反覆使用、多數人知曉的、經過分類的、代碼設計經驗的總結”一點也沒錯,在開發過程中通過滲入一些設計模式,我們的設計效果又會怎麼樣呢?話不多說,直接進入正題吧!
一、設計模式的分類
GOF一共總結了23套設計模式,大致可以分為以下三類:
- 創造型模式
這些設計模式提供了一種在創建對象的同時隱藏創建邏輯的方式,而不是使用 new 運算符直接實例化對象。這使得程式在判斷針對某個給定實例需要創建哪些對象時更加靈活,該類型包括:單件模式、抽象工廠、建造者模式、工廠方法模式和原型模式等5種。
- 結構型模式
這些設計模式關註類和對象的組合。繼承的概念被用來組合介面和定義組合對象獲得新功能的方式,該類型包括:適配器模式、橋接模式、組合模式、裝飾模式、外觀模式、享元模式和代理模式等7種。
- 行為型模式
這些設計模式特別關註對象之間的通信。分為職責鏈模式、命令模式、解釋器模式、迭代器模式、中介者模式、備忘錄模式、觀察者模式、狀態模式、策略模式、模板方法、訪問者模式等11種。
二、設計模式解析
常用設計模式淺析:
1、單件模式
結構圖 :
意圖:保證一個類僅有一個實例,並提供一個訪問它的全局訪問點。
適用性 :
- 當類只能有一個實例而且客戶可以從一個眾所周知的訪問點訪問它時。
- 當這個唯一實例應該是通過子類化可擴展的,並且客戶應該無需更改代碼就能使用一個擴展的實例時。
示意性代碼:
1 //單件模式示意性代碼 2 public class Singleton 3 { 4 //創建私有對象,保證只有一個對象 5 private static Singleton _instance; 6 7 //保護類型的構造函數,子類化可擴展 8 protected Singleton() { } 9 10 //提供公共訪問點 11 public static Singleton Instance() 12 { 13 14 // 使用 'Lazy initialization',為對象實例化 15 if (_instance == null) 16 { 17 _instance = new Singleton(); 18 } 19 20 return _instance; 21 } 22 }Singleton
特點總結:實例對外唯一、子類可以擴展並且提供 一個公共的訪問點訪問。
實際應用:
1 /// <summary> 2 /// 投票選舉 3 /// </summary> 4 public class LoadBalancer 5 { 6 //實例唯一 7 private static LoadBalancer instance; 8 //選舉人 9 private ArrayList servers = new ArrayList(); 10 //隨機數 11 private Random random = new Random(); 12 //用於非同步 13 private static object syncLock = new object(); 14 //保護構造函數,創建時添加選舉人 15 protected LoadBalancer() 16 { 17 servers.Add("ServerI"); 18 servers.Add("ServerII"); 19 servers.Add("ServerIII"); 20 servers.Add("ServerIV"); 21 servers.Add("ServerV"); 22 } 23 //公共訪問點,初始化投票對象 24 public static LoadBalancer GetLoadBalancer() 25 { 26 if (instance == null) 27 { 28 lock (syncLock) 29 { 30 if (instance == null) 31 { 32 instance = new LoadBalancer(); 33 } 34 } 35 } 36 37 return instance; 38 } 39 public string Server 40 { 41 get 42 { 43 int r = random.Next(servers.Count); 44 return servers[r].ToString(); 45 } 46 } 47 }LoadBalancer
1 public class SingletonMain 2 { 3 static void Main() 4 { 5 LoadBalancer b1 = LoadBalancer.GetLoadBalancer(); 6 LoadBalancer b2 = LoadBalancer.GetLoadBalancer(); 7 LoadBalancer b3 = LoadBalancer.GetLoadBalancer(); 8 LoadBalancer b4 = LoadBalancer.GetLoadBalancer(); 9 10 if (b1 == b2 && b2 == b3 && b3 == b4) 11 { 12 Console.WriteLine("Same instance\n"); 13 } 14 15 // Load balance 15 server requests 16 for (int i = 0; i < 15; i++) 17 { 18 Console.WriteLine(b1.Server); 19 } 20 21 Console.ReadKey(); 22 } 23 }SingletonMain
2、抽象工廠
結構圖:
意圖:提供一個創建一系列相關或相互依賴對象的介面,而無需指定它們具體的類。
適用性 :
- 個系統要獨立於它的產品的創建、組合和表示時。
- 一個系統要由多個產品系列中的一個來配置時。
- 當你要強調一系列相關的產品對象的設計以便進行聯合使用時。
- 當你提供一個產品類庫,而只想顯示它們的介面而不是實現時
示意性代碼:
1 public abstract class AbstractFactory 2 { 3 public abstract AbstractProductA CreateProductA(); 4 public abstract AbstractProductB CreateProductB(); 5 } 6 public abstract class AbstractProductA { } 7 public abstract class AbstractProductB 8 { 9 public abstract void Interact(AbstractProductA a); 10 } 11 public class ConcreteFactory1 : AbstractFactory 12 { 13 public override AbstractProductA CreateProductA() 14 { 15 return new ProductA1(); 16 } 17 public override AbstractProductB CreateProductB() 18 { 19 return new ProductB1(); 20 } 21 } 22 public class ConcreteFactory2 : AbstractFactory 23 { 24 public override AbstractProductA CreateProductA() 25 { 26 return new ProductA2(); 27 } 28 public override AbstractProductB CreateProductB() 29 { 30 return new ProductB2(); 31 } 32 } 33 public class ProductA1 : AbstractProductA { } 34 public class ProductA2 : AbstractProductA { } 35 public class ProductB1 : AbstractProductB 36 { 37 public override void Interact(AbstractProductA a) 38 { 39 Console.WriteLine(this.GetType().Name + " interacts with " + 40 a.GetType().Name); 41 } 42 } 43 public class ProductB2 : AbstractProductB 44 { 45 public override void Interact(AbstractProductA a) 46 { 47 Console.WriteLine(this.GetType().Name + " interacts with " + 48 a.GetType().Name); 49 } 50 }AbstractFactory
1 public class Client 2 { 3 private AbstractProductA _abstractProductA; 4 private AbstractProductB _abstractProductB; 5 6 // Constructor 7 public Client(AbstractFactory factory) 8 { 9 _abstractProductB = factory.CreateProductB(); 10 _abstractProductA = factory.CreateProductA(); 11 } 12 13 public void Run() => _abstractProductB.Interact(_abstractProductA); 14 }Client
1 class AbstractFactoryMain 2 { 3 public static void Main() 4 { 5 // Abstract factory #1 6 AbstractFactory factory1 = new ConcreteFactory1(); 7 Client c1 = new Client(factory1); 8 c1.Run(); 9 10 // Abstract factory #2 11 AbstractFactory factory2 = new ConcreteFactory2(); 12 Client c2 = new Client(factory2); 13 c2.Run(); 14 15 Console.ReadKey(); 16 } 17 }AbstractFactoryMain
特點總結:抽象,多態,一系列相關關聯。
3、代理模式
結構圖:
意圖:為其他對象提供一種代理以控制對這個對象的訪問。
適用性 :
- 在需要用比較通用和複雜的對象指針代替簡單的指針的時候,使用 Proxy 模式。
示意性代碼:
1 public abstract class Subject 2 { 3 public abstract void Request(); 4 } 5 6 public class RealSubject : Subject 7 { 8 public override void Request() 9 { 10 Console.WriteLine("Called RealSubject.Request()"); 11 } 12 } 13 14 public class Proxy : Subject 15 { 16 RealSubject realSubject; 17 18 public override void Request() 19 { 20 // Use 'lazy initialization' 21 if (realSubject == null) 22 { 23 realSubject = new RealSubject(); 24 } 25 26 realSubject.Request(); 27 } 28 }Proxy
實際應用:
1 /// <summary> 2 /// Subject介面 3 /// </summary> 4 public interface IMath 5 { 6 //加法操作 7 double Add(double x, double y); 8 //減法操作 9 double Sub(double x, double y); 10 //乘法操作 11 double Mul(double x, double y); 12 //除法操作 13 double Div(double x, double y); 14 } 15 16 /// <summary> 17 /// 具體實現類 18 /// </summary> 19 public class Math : IMath 20 { 21 public double Add(double x, double y) 22 { 23 return x + y; 24 } 25 public double Sub(double x, double y) 26 { 27 return x - y; 28 } 29 public double Mul(double x, double y) 30 { 31 return x * y; 32 } 33 public double Div(double x, double y) 34 { 35 return x / y; 36 } 37 } 38 /// <summary> 39 /// 代理類 40 /// </summary> 41 public class MathProxy : IMath 42 { 43 Math math; 44 public MathProxy() { math = new Math(); } 45 46 public double Add(double x, double y) { return math.Add(x, y); } 47 public double Sub(double x, double y) { return math.Sub(x, y); } 48 public double Mul(double x, double y) { return math.Mul(x, y); } 49 public double Div(double x, double y) { return math.Div(x, y); } 50 }MathProxy
4、觀察者模式
結構圖:
意圖:定義對象間的一種一對多的依賴關係,當一個對象的狀態發生改變時, 所有依賴於它的對象都得到通知並被自動更新。
適用性 :
-
當一個抽象模型有兩個方面, 其中一個方面依賴於另一方面。將這二者封裝在獨立的對象中以使它們可以各自獨立地改變和復用
-
當對一個對象的改變需要同時改變其它對象, 而不知道具體有多少對象有待改變。
-
當一個對象必須通知其它對象,而它又不能假定其它對象是誰。換言之, 你不希望這些對象是緊密耦合的。
示意性代碼:
1 /// <summary> 2 /// 操作抽象類 3 /// </summary> 4 public abstract class Subject 5 { 6 //觀察者數組 7 private ArrayList observers = new ArrayList(); 8 //添加觀察者 9 public void Attach(Observer observer) => observers.Add(observer); 10 //刪除觀察者 11 public void Detach(Observer observer) => observers.Remove(observer); 12 //通知觀察者們 13 public void Notify() 14 { 15 foreach (Observer o in observers) 16 { 17 o.Update(); 18 } 19 } 20 } 21 /// <summary> 22 /// 具體操作類 23 /// </summary> 24 public class ConcreteSubject : Subject 25 { 26 // Property 27 public string SubjectState { get; set; } 28 } 29 /// <summary> 30 /// 觀察者類 31 /// </summary> 32 public abstract class Observer 33 { 34 //更新 35 public abstract void Update(); 36 } 37 38 /// <summary> 39 /// 具體的觀察者 40 /// </summary> 41 public class ConcreteObserver : Observer 42 { 43 private string name; 44 private string observerState; 45 46 // Constructor 47 public ConcreteObserver(ConcreteSubject subject, string name) 48 { 49 this.Subject = subject; 50 this.name = name; 51 } 52 53 public override void Update() 54 { 55 observerState = Subject.SubjectState; 56 Console.WriteLine("Observer {0}'s new state is {1}", name, 57 observerState); 58 } 59 60 // Property 61 public ConcreteSubject Subject { get; set; } 62 }Observer
實際應用:
1 /// <summary> 2 /// 拍賣類 3 /// </summary> 4 public abstract class Stock 5 { 6 protected string symbol; 7 protected double price; 8 private ArrayList investors = new ArrayList(); 9 10 public Stock(string symbol, double price) 11 { 12 this.symbol = symbol; 13 this.price = price; 14 } 15 16 public void Attach(Investor investor) 17 { 18 investors.Add(investor); 19 } 20 public void Detach(Investor investor) 21 { 22 investors.Remove(investor); 23 } 24 25 public void Notify() 26 { 27 foreach (Investor investor in investors) 28 { 29 investor.Update(this); 30 } 31 Console.WriteLine(""); 32 } 33 34 // Properties 35 public double Price 36 { 37 get 38 { 39 return price; 40 } 41 set 42 { 43 price = value; 44 Notify(); 45 } 46 } 47 48 public string Symbol 49 { 50 get 51 { 52 return symbol; 53 } 54 set 55 { 56 symbol = value; 57 } 58 } 59 } 60 /// <summary> 61 /// IBM拍賣 62 /// </summary> 63 public class IBM : Stock 64 { 65 public IBM(string symbol, double price) : base(symbol, price) 66 { 67 } 68 } 69 /// <summary> 70 /// 投資商介面 71 /// </summary> 72 interface IInvestor { void Update(Stock stock); } 73 ///