觀察者模式(Observer):
指多個物件間存在一對多的依賴關系,當一個物件的狀態發生改變時,所有依賴于它的物件都得到通知并被自動更新,
觀察者模式的角色:
1)抽象目標(Subject):也叫抽象目標類,它提供了一個用于保存觀察者物件的聚集類和增加、洗掉觀察者物件的方法,以及通知所有觀察者的抽象方法,
2)具體目標(ConcreteSubject):也叫具體目標類,它實作抽象目標中的通知方法,當具體主題的內部狀態發生改變時,通知所有注冊過的觀察者物件,
3)抽象觀察者(Observer):它是一個抽象類或介面,它包含了一個更新自己的抽象方法,當接到具體主題的更改通知時被呼叫,
4)具體觀察者(ConcreteObserver):實作抽象觀察者中定義的抽象方法,以便在得到目標的更改通知時更新自身的狀態,
1 internal class Program 2 { 3 private static void Main(string[] args) 4 { 5 Subject subject = new ConcreteSubject(); 6 Observer observer1 = new ConcreteObserver1(); 7 Observer observer2 = new ConcreteObserver2(); 8 subject.Attach(observer1); 9 subject.Attach(observer2);10 subject.Notify();11 }12 }13 14 /// <summary>15 /// 抽象目標16 /// </summary>17 internal abstract class Subject18 {19 /// <summary>20 /// 新增觀察者21 /// </summary>22 /// <param name="o"></param>23 public abstract void Attach(Observer o);24 25 /// <summary>26 /// 洗掉觀察者27 /// </summary>28 /// <param name="o"></param>29 public abstract void Detach(Observer o);30 31 /// <summary>32 /// 通知觀察者33 /// </summary>34 public abstract void Notify();35 }36 37 /// <summary>38 /// 抽象觀察者39 /// </summary>40 internal abstract class Observer41 {42 public abstract void update();43 }44 45 /// <summary>46 /// 具體目標47 /// </summary>48 internal class ConcreteSubject : Subject49 {50 private System.Collections.Generic.List<Observer> observers51 = new System.Collections.Generic.List<Observer>();52 53 public override void Attach(Observer o)54 {55 if (o != null)56 observers.Add(o);57 }58 59 public override void Detach(Observer o)60 {61 if (o != null)62 observers.Remove(o);63 }64 65 public override void Notify()66 {67 Console.WriteLine("目標發生變化");68 foreach (var observer in observers)69 {70 observer.update();71 }72 }73 }74 75 /// <summary>76 /// 具體觀察者177 /// </summary>78 internal class ConcreteObserver1 : Observer79 {80 public override void update()81 {82 Console.WriteLine("觀察者1更新");83 }84 }85 86 /// <summary>87 /// 具體觀察者288 /// </summary>89 internal class ConcreteObserver2 : Observer90 {91 public override void update()92 {93 Console.WriteLine("觀察者2更新");94 }95 }
事例:
學校的“鈴”是事件源和目標,"學生"是事件監聽器和具體觀察者,"鈴聲"是事件類,當下課時間到,會觸發鈴發聲,這時會生成“鈴聲”事件;學生就會做一些事情,,,
1 internal class Program 2 { 3 private static void Main(string[] args) 4 { 5 // 創建下課鈴聲 6 Bell subject = new FinishClassBell(); 7 // 創建觀察者 8 Observer xiaoming = new XiaoMing(); 9 Observer xiaohong = new XiaoHong(); 10 Observer xiaowang = new XiaoWang(); 11 // 觀察者隨著聽著下課鈴 12 subject.Attach(xiaoming); 13 subject.Attach(xiaohong); 14 subject.Attach(xiaowang); 15 // 下課鈴響了,通知大家 16 subject.Notify(); 17 } 18 } 19 20 /// <summary> 21 /// 鈴聲:抽象目標 22 /// </summary> 23 internal abstract class Bell 24 { 25 /// <summary> 26 /// 新增觀察者 27 /// </summary> 28 /// <param name="o"></param> 29 public abstract void Attach(Observer o); 30 31 /// <summary> 32 /// 洗掉觀察者 33 /// </summary> 34 /// <param name="o"></param> 35 public abstract void Detach(Observer o); 36 37 /// <summary> 38 /// 通知觀察者 39 /// </summary> 40 public abstract void Notify(); 41 } 42 43 /// <summary> 44 /// 同學下課做事情:抽象觀察者 45 /// </summary> 46 internal abstract class Observer 47 { 48 public abstract void DoSomeThings(); 49 } 50 51 /// <summary> 52 /// 下課鈴聲:具體目標 53 /// </summary> 54 internal class FinishClassBell : Bell 55 { 56 private System.Collections.Generic.List<Observer> observers 57 = new System.Collections.Generic.List<Observer>(); 58 59 public override void Attach(Observer o) 60 { 61 if (o != null) 62 observers.Add(o); 63 } 64 65 public override void Detach(Observer o) 66 { 67 if (o != null) 68 observers.Remove(o); 69 } 70 71 public override void Notify() 72 { 73 Console.WriteLine("鈴聲響了..."); 74 foreach (var observer in observers) 75 { 76 observer.DoSomeThings(); 77 } 78 } 79 } 80 81 /// <summary> 82 /// 小明同學 83 /// </summary> 84 internal class XiaoMing : Observer 85 { 86 public override void DoSomeThings() 87 { 88 Console.WriteLine("小明同學:下課打籃球"); 89 } 90 } 91 92 /// <summary> 93 /// 小紅同學 94 /// </summary> 95 internal class XiaoHong : Observer 96 { 97 public override void DoSomeThings() 98 { 99 Console.WriteLine("小紅同學:嗚嗚嗚,還有一節課");100 }101 }102 103 /// <summary>104 /// 小王同學105 /// </summary>106 internal class XiaoWang : Observer107 {108 public override void DoSomeThings()109 {110 Console.WriteLine("小王同學:餓死了,開吃...");111 }112 }
觀察者模式的應用場景:
1)物件間存在一對多關系,一個物件的狀態發生改變會影響其他物件,
2)當一個抽象模型有兩個方面,其中一個方面依賴于另一方面時,可將這二者封裝在獨立的物件中以使它們可以各自獨立地改變和復用,
觀察者模式的優缺點:
優點:觀察者和被觀察者是抽象耦合的;建立的一套觸發機制,
缺點:
1)如果一個被觀察者物件有很多的直接和間接的觀察者的話,將所有的觀察者都通知到會花費很多時間,
2)如果在觀察者和觀察目標之間有回圈依賴的話,觀察目標會觸發它們之間進行回圈呼叫,可能導致系統崩潰,
3)觀察者模式沒有相應的機制讓觀察者知道所觀察的目標物件是怎么發生變化的,而僅僅只是知道觀察目標發生了變化,
.NET中觀察者模式的應用:
1 // 委托充當訂閱者介面類 2 public delegate void NotifyEventHandler(object sender); 3 4 // 抽象訂閱號類 5 public class TenXun 6 { 7 public NotifyEventHandler NotifyEvent; 8 9 public string Symbol { get; set; }10 public string Info { get; set; }11 public TenXun(string symbol, string info)12 {13 this.Symbol = symbol;14 this.Info = info;15 }16 17 // 新增對訂閱號串列的維護操作18 public void AddObserver(NotifyEventHandler ob)19 {20 NotifyEvent += ob;21 }22 // 洗掉對訂閱號串列的維護操作23 public void RemoveObserver(NotifyEventHandler ob)24 {25 NotifyEvent -= ob;26 }27 // 推送訊息28 public void Update()29 {30 if (NotifyEvent != null)31 {32 NotifyEvent(this);33 }34 }35 }36 37 // 具體訂閱號類38 public class TenXunGame : TenXun39 {40 public TenXunGame(string symbol, string info)41 : base(symbol, info)42 {43 }44 }45 46 // 具體訂閱者類47 public class Subscriber48 {49 public string Name { get; set; }50 public Subscriber(string name)51 {52 this.Name = name;53 }54 55 public void ReceiveAndPrint(Object obj)56 {57 TenXun tenxun = obj as TenXun;58 59 if (tenxun != null)60 {61 Console.WriteLine("Notified {0} of {1}'s" + " Info is: {2}", Name, tenxun.Symbol, tenxun.Info);62 }63 }64 }65 66 static void Main(string[] args)67 {68 TenXun tenXun = new TenXunGame("TenXun Game", "Have a new game published ....");69 Subscriber lh = new Subscriber("Learning Hard");70 Subscriber tom = new Subscriber("Tom");71 72 // 添加訂閱者73 tenXun.AddObserver(new NotifyEventHandler(lh.ReceiveAndPrint));74 tenXun.AddObserver(new NotifyEventHandler(tom.ReceiveAndPrint));75 tenXun.Update();76 77 Console.WriteLine("-----------------------------------");78 Console.WriteLine("移除Tom訂閱者");79 tenXun.RemoveObserver(new NotifyEventHandler(tom.ReceiveAndPrint));80 tenXun.Update();81 }
從上面代碼可以看出,使用事件和委托實作的觀察者模式中,減少了訂閱者介面類的定義,此時,.NET中的委托正式充到訂閱者介面類的角色,使用委托和事件,確實簡化了觀察者模式的實作,減少了一個IObserver介面的定義,
參考:https://www.cnblogs.com/zhili/p/ObserverPattern.html
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/42129.html
標籤:設計模式
上一篇:行為型設計模式(上)
下一篇:迭代器模式
