- A+
观察者模式 Observer
Intro
观察者模式又叫做 发布订阅(Publish/Subscribe)模式
观察者模式定义了一种一对多的依赖关系,让多个观察者同时监听某一主题对象。
这个主题对象在状态发生变化时,会通知所有观察者对象,使得他们能够自动更新自己。
使用场景
观察者模式所做的工作其实就是在解耦,让耦合的双方都依赖于抽象而不是具体,从而使得各自的变化都不会影响另一边的变化。
当一个对象的改变需要改变其他对象的时候,而且它不知道具体有多少对象有待改变的时候,应该考虑使用观察者模式。
一个抽象模型有两方面,其中一方面依赖于另一方面,这时用观察者模式可以将这两者封装在独立的对象中使得他们各自独立地改变和复用。
Sample
public interface ISubject { void Notify(); string SubjectState { get; set; } } public class Boss : ISubject { private readonly IList<Observer> _observers = new List<Observer>(); public void Attach(Observer observer) { _observers.Add(observer); } public void Detach(Observer observer) { _observers.Remove(observer); } public void Notify() { foreach (var observer in _observers) { observer.Update(); } } public string SubjectState { get; set; } } public abstract class Observer { protected string Name; protected ISubject Subject; protected Observer(string name, ISubject subject) { Name = name; Subject = subject; } public abstract void Update(); } public class StockObserver : Observer { public StockObserver(string name, ISubject subject) : base(name, subject) { } public override void Update() { Console.WriteLine($"{Name} {Subject.SubjectState} 关闭股票行情,继续工作"); } } public class NBAObserver : Observer { public NBAObserver(string name, ISubject subject) : base(name, subject) { } public override void Update() { Console.WriteLine($"{Name} {Subject.SubjectState} 关闭 NBA 直播,继续工作"); } } var boss = new Boss(); var stockObserver = new StockObserver("魏关姹", boss); var nbaObserver = new NBAObserver("易管查", boss); boss.Attach(stockObserver); boss.Attach(nbaObserver); boss.Detach(stockObserver); boss.SubjectState = "老板我胡汉三回来了"; boss.Notify();
借助 event(委托) 我们可以实现可以灵活的观察者模式,我们定义了一个新老板来演示事件的方式,来看下面的示例:
public class NewBoss : ISubject { public event Action Update; public void Notify() { Update?.Invoke(); } public string SubjectState { get; set; } } public class GamePlayerObserver { private readonly string _name; private readonly ISubject _subject; public GamePlayerObserver(string name, ISubject subject) { _name = name; _subject = subject; } public void CloseGame() { Console.WriteLine($"{_name} {_subject.SubjectState} 关闭 LOL 游戏,继续工作"); } } var newBoss = new NewBoss(); var stockObserver = new StockObserver("魏关姹", boss); var nbaObserver = new NBAObserver("易管查", boss); var gameObserver = new GamePlayerObserver("西门", newBoss); // 注册通知事件 newBoss.Update += stockObserver.Update; newBoss.Update += nbaObserver.Update; newBoss.Update += gameObserver.CloseGame; newBoss.Update -= stockObserver.Update; newBoss.SubjectState = "老板我胡汉三回来了"; newBoss.Notify();
从上面这个示例可以看到,通过事件的方式,我们可以不要求显示继承于 Observer
这个抽象类,可以更加灵活,扩展性更强,这也是很多类库中会使用事件来扩展的重要原因
More
设计模式要干的事情就是解耦。创建型模式是将创建和使用代码解耦,结构型模式是将不同功能代码解耦,行为型模式是将不同的行为代码解耦,具体到观察者模式,它是将观察者和被观察者代码解耦。
根据应用场景的不同,观察者模式会对应不同的代码实现方式:有同步阻塞的实现方式,也有异步非阻塞的实现方式;有进程内的实现方式,也有跨进程的实现方式。
在对象之间定义一个一对多的依赖,当一个对象状态改变的时候,所有依赖的对象都会自动收到通知。一般情况下,被依赖的对象叫作被观察者(Observable),依赖的对象叫作观察者(Observer)。不过,在实际的项目开发中,这两种对象的称呼是比较灵活的,有各种不同的叫法,比如:Subject-Observer、Publisher-Subscriber、Producer-Consumer、EventEmitter-EventListener、Dispatcher-Listener。不管怎么称呼,只要应用场景符合刚刚给出的定义,都可以看作观察者模式。
EventBus
(事件总线) 就是一个观察者模式的实际应用。