观察者模式(Observer Pattern):定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主体对象,这个主题对象在状态发生变化时,会通知所有观察者。当一个对象改变需要同时改变其他对象,而且他不知道具体有多少对象需要改变的时候,应该考虑使用观察者模式。
观察者模式有四个角色:抽象主题、具体主题、抽象观察者、具体观察者。
ISubject接口(抽象目标):把所有观察者对象的引用保存到一个聚集里,每个主题都可以有任何数量的观察者。含方法Notify,Register,UnRegister(名字可以自己任意取名)
Subject类(实体目标):将有关状态存入具体观察者对象;在具体主题内部状态改变时,给所有登记过的观察者发出通知。实现ISubject接口,一般只有一个
IObservable接口(抽象观察者):为所有的具体观察者定义一个接口,在得到主题通知时更新自己。
Observer类(实体观察者):实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题状态协调。实现IObservable接口,一般有多个
观察者模式中的“注册--通知--注销”图示:
1. 观察者(Observer)将自己(Regiester)注册到被观察对象(Subject)中,被观察对象将观察者放在一个容器(Container)。Container一般为Ilist,Arraylist等数据结构,存放多个IObservable接口变量。
2.当被观察对象(Subject)发生变化时,容器(Container)中的所有观察者(Observer)都得到通知(Notify 方法),此时观察者会自动执行某些方法。
3.当观察者不想继续观察被观察者时,可以注销(UnRegiester方法)
优点: 1、观察者和被观察者是抽象耦合的。 2、建立一套触发机制。
缺点: 1、如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。 2、如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。 3、观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。
实现代码:
抽象观察者(IObservable):
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 /// <summary> 2 /// 只是为了把多个对象产生关系,方便保存和调用 3 /// 方法本身其实没用 4 /// </summary> 5 public interface IObserver 6 { 7 void Action(); 8 }
实体观察者(Observer):
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 public class Baby : IObserver 2 { 3 public void Action() 4 { 5 this.Cry(); 6 } 7 8 public void Cry() 9 { 10 Console.WriteLine("{0} Cry", this.GetType().Name); 11 } 12 }
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 public class Brother : IObserver 2 { 3 public void Action() 4 { 5 this.Turn(); 6 } 7 public void Turn() 8 { 9 Console.WriteLine("{0} Turn", this.GetType().Name); 10 } 11 }
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 public class Chicken : IObserver 2 { 3 public void Action() 4 { 5 this.Woo(); 6 } 7 public void Woo() 8 { 9 Console.WriteLine("{0} Woo", this.GetType().Name); 10 } 11 }
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 public class Dog : IObserver 2 { 3 public void Action() 4 { 5 this.Wang(); 6 } 7 public void Wang() 8 { 9 Console.WriteLine("{0} Wang", this.GetType().Name); 10 } 11 }
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 public class Father : IObserver 2 { 3 public void Action() 4 { 5 this.Roar(); 6 } 7 public void Roar() 8 { 9 Console.WriteLine("{0} Roar", this.GetType().Name); 10 } 11 }
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 public class Mother : IObserver 2 { 3 public void Action() 4 { 5 this.Whisper(); 6 } 7 public void Whisper() 8 { 9 Console.WriteLine("{0} Whisper", this.GetType().Name); 10 } 11 }
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 public class Mouse : IObserver 2 { 3 public void Action() 4 { 5 this.Run(); 6 } 7 public void Run() 8 { 9 Console.WriteLine("{0} Run", this.GetType().Name); 10 } 11 }
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 public class Neighbor : IObserver 2 { 3 public void Action() 4 { 5 this.Awake(); 6 } 7 public void Awake() 8 { 9 Console.WriteLine("{0} Awake", this.GetType().Name); 10 } 11 }
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 public class Stealer : IObserver 2 { 3 public void Action() 4 { 5 this.Hide(); 6 } 7 public void Hide() 8 { 9 Console.WriteLine("{0} Hide", this.GetType().Name); 10 } 11 }
实体目标(Subject):
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 /// <summary> 2 /// 一只神奇的猫 3 /// 4 /// 猫叫一声之后触发 5 /// baby cry 6 /// brother turn 7 /// dog wang 8 /// father roar 9 /// mother whisper 10 /// mouse run 11 /// neighbor awake 12 /// stealer hide 13 /// 14 /// </summary> 15 public class Cat 16 { 17 public void Miao() 18 { 19 Console.WriteLine("{0} Miao.....", this.GetType().Name); 20 21 new Mouse().Run();//依赖 22 new Chicken().Woo(); 23 new Baby().Cry(); 24 new Brother().Turn(); 25 new Dog().Wang(); 26 new Father().Roar(); 27 new Mother().Whisper(); 28 //new Mouse().Run(); 29 new Neighbor().Awake(); 30 //new Stealer().Hide(); 31 } 32 //依赖太多,任何一个对象改动,都会导致Cat变化 33 //违背了单一职责,不仅自己miao 还要触发各种动作,不稳定 34 //加一个/减一个/调整顺序 Cat都得改 35 36 //Cat职责:1 Miao 2 触发一系列动作 这是需求 37 //实现上,其实多了一个,3 指定动作 38 39 //Cat不稳定--这一堆对象--甩锅--自己不写让别人传递 40 private List<IObserver> _ObserverList = new List<IObserver>(); 41 public void AddObserver(IObserver observer) 42 { 43 this._ObserverList.Add(observer); 44 } 45 public void MiaoObserver() 46 { 47 Console.WriteLine("{0} MiaoObserver.....", this.GetType().Name); 48 if (this._ObserverList != null && this._ObserverList.Count > 0) 49 { 50 foreach (var item in this._ObserverList) 51 { 52 item.Action(); 53 } 54 } 55 } 56 57 public event Action MiaoHandler; 58 public void MiaoEvent() 59 { 60 Console.WriteLine("{0} MiaoEvent.....", this.GetType().Name); 61 if (this.MiaoHandler != null) 62 { 63 foreach (Action item in this.MiaoHandler.GetInvocationList()) 64 { 65 item.Invoke(); 66 } 67 } 68 } 69 70 }
前端调用:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 { 2 Console.WriteLine("***************Common******************"); 3 Cat cat = new Cat(); 4 cat.Miao(); 5 } 6 { 7 Console.WriteLine("***************Observer******************"); 8 Cat cat = new Cat(); 9 cat.AddObserver(new Mouse()); 10 cat.AddObserver(new Chicken()); 11 cat.AddObserver(new Baby()); 12 cat.AddObserver(new Brother()); 13 cat.AddObserver(new Dog()); 14 cat.AddObserver(new Father()); 15 cat.AddObserver(new Mother()); 16 cat.AddObserver(new Mouse()); 17 cat.AddObserver(new Neighbor()); 18 cat.AddObserver(new Stealer()); 19 cat.MiaoObserver(); 20 } 21 22 { 23 Console.WriteLine("***************Observer******************"); 24 Cat cat = new Cat(); 25 cat.MiaoHandler += new Baby().Cry; 26 cat.MiaoHandler += new Brother().Turn; 27 cat.MiaoHandler += new Dog().Wang; 28 cat.MiaoHandler += new Stealer().Hide; 29 cat.MiaoHandler += new Neighbor().Awake; 30 cat.MiaoHandler += new Father().Roar; 31 cat.MiaoEvent(); 32 }
交互的对象之间应尽量设计成松耦合的
松耦合设计可以让我们设计出这样的系统: 因为对象之间的相互依存减小了, 所以系统可以轻松处理变化
松耦合系统通常是基于消息的系统,此时客户端和远程服务并不知道对方是如何实现的。客户端和服务之间的通讯由消息的架构支配。只要消息符合协商的架构,则客户端或服务的实现就可以根据需要进行更改,而不必担心会破坏对方
当两个对象是松耦合的时候, 他们可以进行交互, 但是却几乎不了解对方.
观察者模式下的被观察者(Subject)和观察者(Observers)就是松耦合设计的对象. 这是因为:
-
-
被观察者(Subject)只知道观察者实现了某个接口
-
可以随时添加观察者
-
添加新类型观察者的时候不需要修改被观察者
-
可以复用观察者或者被观察者
-
如果被观察者或观察者发生变化了, 那么这些变化不会影响到对方
-
使用委托的时候, 通常会有两个角色出现: 广播者(被观察者)和订阅者(观察者) [观察者模式]
广播者包含一个委托field, 广播者决定何时广播, 它通过调用委托进行广播.
订阅者就是方法的目标接收者.订阅者可以决定何时开始和结束监听, 是通过在广播者的委托上使用+=和-=操作符来实现的.
订阅者之间互相不了解, 不干扰.
event就是为上述模型所存在的, 它只把上述模型所必须的功能从委托里暴露出来. 它的主要目的就是防止订阅者之间相互干扰.
最简单声明event的方法就是在委托成员前面加上event关键字
本文参考文档:
https://www.runoob.com/design-pattern/observer-pattern.html
https://www.cnblogs.com/abcdwxc/archive/2007/09/19/898856.html
https://www.cnblogs.com/zhiyong-ITNote/p/10970067.html
https://mp.weixin.qq.com/s/XkfiFKPTbOy6kGGzfQOFpA