今天我們來講一下觀察者模式。還是老樣子,給大家一個案例。 一、案例 在我們懷念的學生時代,我們會有這麼一個現象,當在教室里上自習的時候,讓一個同學把風,我們在教室里玩,當老師來的時候,讓那個同學給我們說一聲。 好,下麵我們就用簡單的控制台應用程式來實現上述的場景(一個把風的同學,兩個玩耍的同學) 客 ...
今天我們來講一下觀察者模式。還是老樣子,給大家一個案例。
一、案例
在我們懷念的學生時代,我們會有這麼一個現象,當在教室里上自習的時候,讓一個同學把風,我們在教室里玩,當老師來的時候,讓那個同學給我們說一聲。
好,下麵我們就用簡單的控制台應用程式來實現上述的場景(一個把風的同學,兩個玩耍的同學)
1 /// <summary> 2 /// 把風同學類 3 /// </summary> 4 class Secretary 5 { 6 //有幾個同學請把風的幫忙,於是就給集合增加幾個對象 7 private IList<Observer> obs = new List<Observer>(); 8 private string _action; 9 10 public void Attach(Observer ob) 11 { 12 obs.Add(ob); 13 } 14 15 /// <summary> 16 /// 老師回來時,給所有登記的同學們發通知。 17 /// </summary> 18 public void Notify() 19 { 20 foreach (var ob in obs) 21 { 22 ob.Update(); 23 } 24 } 25 /// <summary> 26 /// 狀態 27 /// </summary> 28 public string SecretoryAction 29 { 30 get { return _action; } 31 set { _action = value; } 32 } 33 } 34 35 /// <summary> 36 /// 玩耍的同學類 37 /// </summary> 38 class Observer 39 { 40 private string name; 41 private Secretary sub; 42 43 public Observer(string name, Secretary sub) 44 { 45 this.name = name; 46 this.sub = sub; 47 } 48 /// <summary> 49 /// 得到把風的通知 50 /// </summary> 51 public void Update() 52 { 53 Console.WriteLine($"{sub.SecretoryAction}{name}別玩游戲了"); 54 } 55 }
客戶端:
1 public static void Main() 2 { 3 //把風的 4 Secretary s = new Secretary(); 5 //小王同學 6 Observer ob1 = new Observer("小王", s); 7 //小李同學 8 Observer ob2 = new Observer("小李", s); 9 //把風的記下兩位同學 10 s.Attach(ob1); 11 s.Attach(ob2); 12 //發現老師來了 13 s.SecretoryAction = "老師回來了!"; 14 //通知兩個同學 15 s.Notify(); 16 Console.ReadKey(); 17 }
嗯,上述代碼我們發現了一個問題,就是 把風的這個同學的類 和 玩耍的同學的類,耦合性太強了。把風類需要增加玩耍的同學,同學類需要把風的通知。
這麼強的耦合,如果我們需要添加一個同學進來,那兩邊都需要修改了,如果還要通知唱歌同學老師來了,咋辦?這其實違背了設計的兩個原則,開放-封閉原則,依賴倒轉原則。
我們的程式都應該依賴於抽象,而不是相互依賴。
二、演繹
1、第一步演繹
好,下麵我們來修改一下上述的代碼。增加一個抽象的觀察者類
1 /// <summary> 2 /// 抽象的觀察者 3 /// </summary> 4 public abstract class Observer 5 { 6 protected string name; 7 protected Secretary sub; 8 9 public Observer(string name, Secretary sub) 10 { 11 this.name = name; 12 this.sub = sub; 13 } 14 15 public abstract void Update(); 16 }
讓具體的觀察者繼承這個抽象類
1 /// <summary> 2 /// 具體的觀察者1(玩游戲的) 3 /// </summary> 4 public class Observer1 : Observer 5 { 6 public Observer1(string name, Secretary sub) : base(name, sub) 7 { 8 } 9 10 public override void Update() 11 { 12 Console.WriteLine($"{sub.SecretoryAction}{name},別唱歌了。"); 13 } 14 } 15 /// <summary> 16 /// 具體的觀察者2(唱歌的) 17 /// </summary> 18 public class Observer2 : Observer 19 { 20 public Observer2(string name, Secretary sub) : base(name, sub) 21 { 22 } 23 24 public override void Update() 25 { 26 Console.WriteLine($"{sub.SecretoryAction}{name},別玩游戲了。"); 27 } 28 }
把風同學類的代碼基本不變
1 /// <summary> 2 /// 把風同學類 3 /// </summary> 4 public class Secretary 5 { 6 //有幾個同學請把風的幫忙,於是就給集合增加幾個對象 7 private IList<Observer> obs = new List<Observer>(); 8 private string _action; 9 10 public void Attach(Observer ob) 11 { 12 obs.Add(ob); 13 } 14 15 /// <summary> 16 /// 老師回來時,給所有登記的同學們發通知。 17 /// </summary> 18 public void Notify() 19 { 20 foreach (var ob in obs) 21 { 22 ob.Update(); 23 } 24 } 25 /// <summary> 26 /// 狀態 27 /// </summary> 28 public string SecretoryAction 29 { 30 get { return _action; } 31 set { _action = value; } 32 } 33 }
客戶端調用
1 public static void Main() 2 { 3 //把風的 4 Secretary s = new Secretary(); 5 //玩耍小王同學 6 Observer ob1 = new Observer1("小王", s); 7 //玩耍小李同學 8 Observer ob2 = new Observer1("小李", s); 9 //玩耍小李同學 10 Observer ob3 = new Observer2("小張", s); 11 //把風的記下三位同學 12 s.Attach(ob1); 13 s.Attach(ob2); 14 s.Attach(ob3); 15 //發現老師來了 16 s.SecretoryAction = "老師回來了!"; 17 //通知三位同學 18 s.Notify(); 19 Console.ReadKey(); 20 }
2、第二步演繹
既然觀察者我們抽象出一個抽象類來了,那麼我們仔細觀察一下,把風的同學這個類是一個具體的類,也可以抽象出來。還有,如果哪個同學跟把風的那個同學鬧矛盾了,可以不給他通知了,嘿嘿。所以可以加一個刪除方法。好了,看一下代碼吧
1 /// <summary> 2 /// 把風類抽象出來的介面 3 /// </summary> 4 interface Subject 5 { 6 void Attach(Observer ob); 7 void Detach(Observer ob); 8 9 string SecretoryAction 10 { 11 get; 12 set; 13 } 14 }
具體的把風同學的類可繼承這個介面
1 /// <summary> 2 /// 把風同學類 3 /// </summary> 4 public class Secretary : Subject 5 { 6 private IList<Observer> obs = new List<Observer>(); 7 private string action; 8 public void Attach(Observer ob) 9 { 10 obs.Add(ob); 11 } 12 13 public void Detach(Observer ob) 14 { 15 obs.Remove(ob); 16 } 17 18 public void Notify() 19 { 20 foreach (var o in obs) 21 { 22 o.Update(); 23 } 24 } 25 public string SecretoryAction 26 { 27 get { return action; } 28 set { action = value; } 29 } 30 }
客戶端:
1 public static void Main() 2 { 3 //把風的 4 Secretary s = new Secretary(); 5 //玩耍小王同學 6 Observer ob1 = new Observer1("小王", s); 7 //玩耍小李同學 8 Observer ob2 = new Observer1("小李", s); 9 //玩耍小李同學 10 Observer ob3 = new Observer2("小張", s); 11 //把風的記下三位同學 12 s.Attach(ob1); 13 s.Attach(ob2); 14 s.Attach(ob3); 15 //發現老師來了 16 s.SecretoryAction = "老師回來了!"; 17 //通知三位同學 18 s.Notify(); 19 Console.ReadKey(); 20 }
ok,觀察者模式就講完了,下麵我們來總結一下:
觀察者模式:又叫 發佈-訂閱模式,他定義了一種一對多的依賴關係,讓多個觀察者對象共同監聽同一個主題對象,當主題對象狀態發生變化時,會通知所有觀察者對象,使他們能夠自動更新自己。
觀察者模式所做的事情就是解耦,讓耦合的雙方都依賴於抽象,而不依賴於具體,從而使得自己的變化不會影響到另一邊。
好了,觀察者模式我麽你就說到這裡了,下一篇博文,將會講 抽象工廠模式
本系列將持續更新,喜歡的小伙伴可以點一下關註和推薦,謝謝大家的支持。