观察者模式
背景
在软件系统中进场遇到这类需求:当一个对象的状态发生改变,某些与它相关的对象也要随之做出相应的变化。这是建立一种 对象域对象之前的依赖关系,一个对象发生变化时将自动通知其他对象,其他对象将做出反应。
我们将发生改变的对象称为观察目标,将被通知的对象称为观察者,一个观察目标可以对应多个观察者,而且这些观察者之间没有相互关系,之后可以根据需要增加和删除贯彻着,是的系统更易于扩展,这就是观察者模式的产生背景。
概念介绍
观察者模式(Observer Pattern):定义对象之间的一种 一对多依赖关系,使得每当一个对象状态发生改变时,其他依赖对象皆得到通知并被自动更新。观察者模式是一种对象行为型模式。
生活场景
所有浏览器事件(鼠标悬浮,按键等事件)都是观察者模式的例子。
模式特点
1.模式组成
在观察着模式中,通常包含以下角色:
a.目标(Subject)
b.观察目标(ConcresteSubject)
c.观察者(Observer)
d.具体观察者(ConcreteObserver)
2.UML类图
3.优点
- 观察者模式可以实现 表示层和数据逻辑层的分离,并降低观察目标和观察者之间的耦合度;
- 观察者模式支持简单广播通信,自动通知所有已经订阅过的对象;
- 观察者模式 符合开闭原则的要求;
- 观察目标和观察者之间的抽象耦合关系能够单独扩展以及中庸。
4.缺点
- 当一个观察目标有多个直接或间接的观察者时,通知所有观察者的过程将会话费很多时间。
- 当观察目标和观察者之间存在循环依赖时,观察目标会触发他们之间进行循环调用,可能导致系统崩溃。
- 观察者模式缺少相应机制,让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。
使用场景
在以下情况下可以使用观察者模式:
- 在一个抽象模型中,一个对象的行为 依赖于另一个对象的状态。即当目标对象的状态发生改变是,会直接影响到观察者的行为;
- 一个对象需要通知其他对象发生反应,但不知道对象是谁。
- 需要在系统中创建一个触发链时,A对象的行为将影响B,B对象的行为将影响C对象……,可以使用观察者模式创建一种链式触发机制。
实战示例
1.定义观察目标接口 和观察者接口
//观察目标接口 interface Subject { addObserver: (observer:Observer) => void; deleteObserver:(observver:Observer) => void; notifyObservers:() => void; } //观察者接口 interface Observer { notify:() => void; }
2.定义具体观察目标
//具体观察目标类 class ConcreteSubject implements Subject { private observers: Observer[] = []; //添加观察者 public addObserver(observer:Observer): void { console.log(observer, "is pushed~~"); this.observers.push(observer); } //删除观察者 public deleteObserver(observer:Observer): void { console.log(observer,"have deleted~~"); const idx:number = this.observers.indexOf(observer); ~idx && this.observsers.splice(idx,1); } //通知观察者 public notifyObservers(): void { console.log('notify all the observers ',this.observers); this.observers.forEach(observer => { //调用 notify 方法时可以携带指定参数 observer.notify(); }) } }
3.定义 具体观察类
//具体观察类 class ConcreteObserver implements Observer { constructor(private name:string){} notify():void { //可以处理其他逻辑 console.log(`${this.name}has been notified.`); } }
4.测试代码
//测试代码~~~~ function userObserver(): void { const subject: Subject = new ConcreteSubject(); const Leo = new ConcreteObserver('Leo'); const Robin = new ConcreteObserver('Robin'); const Pual = new ConcreteObserver('Pual'); const Lisa = new ConcreteObserver('Lisa'); subject.addObserver(Leo); subject.addObserver(Robin); subject.addObserver(Pual); subject.addObserver(Lisa); subject.notifyObservers(); }