觀察者模式(Observer): 指多個對象間存在一對多的依賴關係,當一個對象的狀態發生改變時,所有依賴於它的對象都得到通知並被自動更新。 觀察者模式的角色: 1)抽象目標(Subject):也叫抽象目標類,它提供了一個用於保存觀察者對象的聚集類和增加、刪除觀察者對象的方法,以及通知所有觀察者的抽象 ...
觀察者模式(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 Subject 18 { 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 Observer 41 { 42 public abstract void update(); 43 } 44 45 /// <summary> 46 /// 具體目標 47 /// </summary> 48 internal class ConcreteSubject : Subject 49 { 50 private System.Collections.Generic.List<Observer> observers 51 = 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 /// 具體觀察者1 77 /// </summary> 78 internal class ConcreteObserver1 : Observer 79 { 80 public override void update() 81 { 82 Console.WriteLine("觀察者1更新"); 83 } 84 } 85 86 /// <summary> 87 /// 具體觀察者2 88 /// </summary> 89 internal class ConcreteObserver2 : Observer 90 { 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 : Observer 107 { 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 : TenXun 39 { 40 public TenXunGame(string symbol, string info) 41 : base(symbol, info) 42 { 43 } 44 } 45 46 // 具體訂閱者類 47 public class Subscriber 48 { 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