概念
The observer pattern defines a one-to-many relationship. When one object updates, it notifies many other objects that it has been updated.
- subject – This is the object that will send out a notification to all of the ‘observers’ who want/need to know that the subject was updated.
- observers – These are the objects that want to know when the subject has changed.
设计模式要干的就是解耦。 创建型模式是将创建和使用代码解耦,结构型是将不同功能代码解耦,行为型模式是将不同代码解耦 具体到观察者就是将观察者和被观察者代码解耦
代码实现
/*** The Subject interface declares a set of methods for managing subscribers.*/interface Subject {// Attach an observer to the subject.attach(observer: Observer): void;// Detach an observer from the subject.detach(observer: Observer): void;// Notify all observers about an event.notify(): void;}/*** The Subject owns some important state and notifies observers when the state* changes.*/class ConcreteSubject implements Subject {/*** @type {number} For the sake of simplicity, the Subject's state, essential* to all subscribers, is stored in this variable.*/public state: number;/*** @type {Observer[]} List of subscribers. In real life, the list of* subscribers can be stored more comprehensively (categorized by event* type, etc.).*/private observers: Observer[] = [];/*** The subscription management methods.*/public attach(observer: Observer): void {const isExist = this.observers.includes(observer);if (isExist) {return console.log('Subject: Observer has been attached already.');}console.log('Subject: Attached an observer.');this.observers.push(observer);}public detach(observer: Observer): void {const observerIndex = this.observers.indexOf(observer);if (observerIndex === -1) {return console.log('Subject: Nonexistent observer.');}this.observers.splice(observerIndex, 1);console.log('Subject: Detached an observer.');}/*** Trigger an update in each subscriber.*/public notify(): void {console.log('Subject: Notifying observers...');for (const observer of this.observers) {observer.update(this);}}/*** Usually, the subscription logic is only a fraction of what a Subject can* really do. Subjects commonly hold some important business logic, that* triggers a notification method whenever something important is about to* happen (or after it).*/public someBusinessLogic(): void {console.log('\nSubject: I\'m doing something important.');this.state = Math.floor(Math.random() * (10 + 1));console.log(`Subject: My state has just changed to: ${this.state}`);this.notify();}}/*** The Observer interface declares the update method, used by subjects.*/interface Observer {// Receive update from subject.update(subject: Subject): void;}/*** Concrete Observers react to the updates issued by the Subject they had been* attached to.*/class ConcreteObserverA implements Observer {public update(subject: Subject): void {if (subject instanceof ConcreteSubject && subject.state < 3) {console.log('ConcreteObserverA: Reacted to the event.');}}}class ConcreteObserverB implements Observer {public update(subject: Subject): void {if (subject instanceof ConcreteSubject && (subject.state === 0 || subject.state >= 2)) {console.log('ConcreteObserverB: Reacted to the event.');}}}/*** The client code.*/const subject = new ConcreteSubject();const observer1 = new ConcreteObserverA();subject.attach(observer1);const observer2 = new ConcreteObserverB();subject.attach(observer2);subject.someBusinessLogic();subject.someBusinessLogic();subject.detach(observer2);subject.someBusinessLogic();
Event Bus/ Event Emitter
class EventEmitter {constructor() {// handlers是一个map,用于存储事件与回调之间的对应关系this.handlers = {}}// on方法用于安装事件监听器,它接受目标事件名和回调函数作为参数on(eventName, cb) {// 先检查一下目标事件名有没有对应的监听函数队列if (!this.handlers[eventName]) {// 如果没有,那么首先初始化一个监听函数队列this.handlers[eventName] = []}// 把回调函数推入目标事件的监听函数队列里去this.handlers[eventName].push(cb)}// emit方法用于触发目标事件,它接受事件名和监听函数入参作为参数emit(eventName, ...args) {// 检查目标事件是否有监听函数队列if (this.handlers[eventName]) {// 这里需要对 this.handlers[eventName] 做一次浅拷贝,主要目的是为了避免通过 once 安装的监听器在移除的过程中出现顺序问题const handlers = this.handlers[eventName].slice()// 如果有,则逐个调用队列里的回调函数handlers.forEach((callback) => {callback(...args)})}}// 移除某个事件回调队列里的指定回调函数off(eventName, cb) {const callbacks = this.handlers[eventName]const index = callbacks.indexOf(cb)if (index !== -1) {callbacks.splice(index, 1)}}// 为事件注册单次监听器once(eventName, cb) {// 对回调函数进行包装,使其执行完毕自动被移除const wrapper = (...args) => {cb(...args)this.off(eventName, wrapper)}this.on(eventName, wrapper)}}
