设计模式 - 观察者模式(Observer Pattern)
定义描述
定义对象间的一种或多种依赖关系,当一个对象发生改变时,所有依赖于它的对象都会被通知自动更新。观察者模式主要角色有目标对象(被观察者),观察者。根据定义描述,我们可以简单的理解成观察者观察目标对象的行为做出相应反应。
举个很经典的例子,猫叫了,主人醒了,老鼠跑了。这里猫就是被观察者,老鼠和主人是观察者。下面是其对应的类图。
优点
1、观察者和被观察者是抽象耦合的。
2、建立一套触发机制。
缺点
1、如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。
2、如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。
3、观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。
使用场景:
- 一个抽象模型有两个方面,其中一个方面依赖于另一个方面。将这些方面封装在独立的对象中使它们可以各自独立地改变和复用。
- 一个对象的改变将导致其他一个或多个对象也发生改变,而不知道具体有多少对象将发生改变,可以降低对象之间的耦合度。
- 一个对象必须通知其他对象,而并不知道这些对象是谁。
- 需要在系统中创建一个触发链,A对象的行为将影响B对象,B对象的行为将影响C对象……,可以使用观察者模式创建一种链式触发机制。
注意事项:
1、很多语言已经有了支持观察者模式的类。
2、避免循环引用。
3、如果顺序执行,某一观察者错误会导致系统卡壳,一般采用异步方式。
ISubject
namespace ConsoleApp3.Observer { public interface ISubject { int GetState(); void SetState(int state); void Notify(); void Attach(IObserver observer); } }
Cat
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ConsoleApp3.Observer { public class Cat : ISubject { private List<IObserver> observers = new List<IObserver>(); public int GetState() { return 1; } public void SetState(int state) { if (state == 0) Console.WriteLine("猫叫了"); Notify(); } public void Notify() { foreach (var observer in observers) { observer.Update(); } } public void Attach(IObserver observer) { observers.Add(observer); } } }
IObserver
namespace ConsoleApp3.Observer { public interface IObserver { void Update(); } }
Mouse
using System; namespace ConsoleApp3.Observer { public class Mouse : IObserver { public Mouse(ISubject subject) { subject.Attach(this); } public void Update() { Console.WriteLine("老鼠跑了"); } } }
Master
using System; namespace ConsoleApp3.Observer { public class Master : IObserver { public Master(ISubject subject) { subject.Attach(this); } public void Update() { Console.WriteLine("主人醒了"); } } }
Demo
ISubject subject = new Cat(); new Mouse(subject); new Master(subject); subject.SetState(0);