前言
前面我们介绍完创建型模式和创建型模式,这篇介绍最后的行为型模式,也是【设计模式】专栏的最后一篇。
一、概述
行为型模式主要用于处理对象之间的交互和职责分配,以实现更灵活的行为和更好的协作。
二、常见的行为型模式
1、观察者模式(Observer Pattern):
定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖它的对象都会得到通知并自动更新。
解释:可以把它想象成一个明星和粉丝的关系,明星(被观察对象)的一举一动(状态改变)都会被粉丝(观察者)关注到,当明星有新动态时,粉丝会收到消息。
代码示范以及解释
// 被观察对象类
class Subject {constructor() {this.observers = [];}// 添加观察者addObserver(observer) {this.observers.push(observer);}// 移除观察者removeObserver(observer) {const index = this.observers.indexOf(observer);if (index!== -1) {this.observers.splice(index, 1);}}// 通知所有观察者notify() {this.observers.forEach(observer => observer.update());}
}// 观察者类
class Observer {constructor(name) {this.name = name;}update() {console.log(`${this.name} has been notified.`);}
}// 使用示例
const subject = new Subject();
const observer1 = new Observer('Fan1');
const observer2 = new Observer('Fan2');subject.addObserver(observer1);
subject.addObserver(observer2);subject.notify();
// 输出:
// Fan1 has been notified.
// Fan2 has been notified.
被观察的对象Subject
- 构造函数
constructor
:
- 初始化一个空数组
this.observers
,用于存储所有注册的观察者。addObserver
方法:
- 接收一个
observer
对象作为参数,将其添加到this.observers
数组中。这就相当于有一个新的观察者开始关注这个被观察对象了。removeObserver
方法:
- 接收一个
observer
对象作为参数,首先使用indexOf
方法查找该观察者在this.observers
数组中的索引。- 如果索引不为 -1(说明该观察者存在于数组中),则使用
splice
方法将其从数组中移除,意味着这个观察者不再关注被观察对象了。notify
方法:
- 遍历
this.observers
数组,对每个观察者调用其update
方法。这样就可以通知所有注册的观察者,让它们执行相应的更新操作。
观察者Observer
- 构造函数
constructor
:
- 接收一个
name
参数,用于标识这个观察者,将其存储在this.name
中。update
方法:
- 当被观察对象调用
notify
方法通知观察者时,这个update
方法会被执行。它会打印出一条消息,表明该观察者已经收到了通知。
代码执行结果解释
- 首先创建一个
Subject
类的实例subject
,表示被观察对象。- 接着创建两个
Observer
类的实例observer1
和observer2
,分别命名为'Fan1'
和'Fan2'
。- 调用
subject.addObserver
方法将observer1
和observer2
添加到subject
的观察者列表中。- 最后调用
subject.notify()
方法,subject
会遍历其观察者列表,依次调用每个观察者的update
方法,因此控制台会输出'Fan1 has been notified.'
和'Fan2 has been notified.'
。
2、策略模式(Strategy Pattern):
定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换。策略模式让算法的变化独立于使用算法的客户。
解释:策略模式定义了一系列的算法,把它们一个个封装起来,并且使它们可相互替换。策略模式让算法的变化独立于使用算法的客户。这就好比你要去上班,有多种出行方式(策略)可供选择,如坐公交、打车、骑自行车等,你可以根据当天的实际情况(如时间、天气等)来动态地选择合适的出行方式,而上班这个行为本身不受具体出行方式的影响。
代码示范以及解释
// 定义不同的策略类
// 公交出行策略
class BusStrategy {travel() {console.log('Taking the bus to work.');}
}
//这是一个公交出行策略类,包含一个 travel 方法。
//当调用 travel 方法时,会在控制台打印出 Taking the bus to work.,表示选择乘坐公交去上班。// 打车出行策略
class TaxiStrategy {travel() {console.log('Taking a taxi to work.');}
}
//这是一个打车出行策略类,同样有一个 travel 方法。
//调用 travel 方法时,会在控制台打印出 Taking a taxi to work.,表示选择打车去上班。// 自行车出行策略
class BicycleStrategy {travel() {console.log('Riding a bicycle to work.');}
}
//这是一个自行车出行策略类,travel 方法会在控制台打印出 Riding a bicycle to work.,表示选择骑自行车去上班。// 环境类,负责使用策略
class Commute {constructor(strategy) {this.strategy = strategy;}setStrategy(strategy) {this.strategy = strategy;}goToWork() {this.strategy.travel();}
}
//构造函数 constructor:
//接收一个 strategy 参数,将传入的策略对象赋值给 this.strategy,表示初始化时使用该策略。
//setStrategy 方法:
//接收一个新的 strategy 参数,将 this.strategy 更新为新的策略对象,从而实现策略的动态切换。
//goToWork 方法:
//调用当前 this.strategy 对象的 travel 方法,执行具体的出行策略。// 使用示例
const busStrategy = new BusStrategy();
const commute = new Commute(busStrategy);
commute.goToWork(); // 输出: Taking the bus to work.const taxiStrategy = new TaxiStrategy();
commute.setStrategy(taxiStrategy);
commute.goToWork(); // 输出: Taking a taxi to work.
执行结果解释
- 首先创建一个
BusStrategy
类的实例busStrategy
,表示公交出行策略。- 接着创建一个
Commute
类的实例commute
,并将busStrategy
作为参数传入,意味着初始化时使用公交出行策略。- 调用
commute.goToWork()
方法,会执行公交出行策略,控制台输出Taking the bus to work.
。- 然后创建一个
TaxiStrategy
类的实例taxiStrategy
,表示打车出行策略。- 调用
commute.setStrategy(taxiStrategy)
方法,将当前的出行策略切换为打车策略。- 再次调用
commute.goToWork()
方法,会执行打车出行策略,控制台输出Taking a taxi to work.
。
3、发布-订阅模式(Publish - Subscribe Pattern)(重点!!)
发布 - 订阅模式和观察者模式类似,但它引入了一个中间者(消息代理),发布者(发布消息的对象)将消息发布到消息代理,订阅者(接收消息的对象)向消息代理订阅感兴趣的消息。这种模式实现了发布者和订阅者之间的解耦。
简单理解:就像一个报社和读者的关系,报社(发布者)负责发布报纸(消息),读者(订阅者)向报社订阅报纸,当有新报纸出版时,报社将报纸发送给订阅的读者。
代码示范以及解释
// 消息代理类
class EventEmitter {constructor() {this.events = {};}// 订阅事件on(eventName, callback) {if (!this.events[eventName]) {this.events[eventName] = [];}this.events[eventName].push(callback);}// 发布事件emit(eventName, ...args) {if (this.events[eventName]) {this.events[eventName].forEach(callback => callback(...args));}}// 取消订阅事件off(eventName, callback) {if (this.events[eventName]) {const index = this.events[eventName].indexOf(callback);if (index!== -1) {this.events[eventName].splice(index, 1);}}}
}// 使用示例
const eventEmitter = new EventEmitter();// 订阅者的回调函数
const callback1 = (message) => {console.log(`Subscriber 1 received: ${message}`);
};const callback2 = (message) => {console.log(`Subscriber 2 received: ${message}`);
};// 订阅事件
eventEmitter.on('news', callback1);
eventEmitter.on('news', callback2);// 发布事件
eventEmitter.emit('news', 'A new article is published!');
// 输出:
// Subscriber 1 received: A new article is published!
// Subscriber 2 received: A new article is published!// 取消订阅
eventEmitter.off('news', callback1);
eventEmitter.emit('news', 'Another new article!');
// 输出:
// Subscriber 2 received: Another new article!
整体功能概述
EventEmitter
类充当消息代理,它允许用户订阅(on
方法)特定的事件,发布(emit
方法)事件,以及取消订阅(off
方法)事件。当事件被发布时,所有订阅该事件的回调函数都会被执行。
消息代理类 EventEmitter
- 构造函数
constructor
:
- 初始化一个空对象
this.events
,用于存储事件及其对应的回调函数数组。每个事件名作为对象的键,对应的值是一个数组,数组中存储着订阅该事件的所有回调函数。on
方法:
- 接收两个参数:
eventName
表示事件的名称,callback
是订阅该事件时要执行的回调函数。- 首先检查
this.events
对象中是否已经存在该事件名。如果不存在,就为该事件名创建一个空数组。- 然后将传入的
callback
函数添加到该事件对应的数组中。这意味着又有一个订阅者订阅了该事件。emit
方法:
- 接收事件名
eventName
和任意数量的参数...args
。- 检查
this.events
对象中是否存在该事件名。如果存在,就遍历该事件对应的回调函数数组,依次调用每个回调函数,并将...args
作为参数传递给它们。这样就实现了事件的发布,通知所有订阅者执行相应的操作。off
方法:
- 接收事件名
eventName
和要取消订阅的回调函数callback
。- 检查
this.events
对象中是否存在该事件名。如果存在,使用indexOf
方法查找该回调函数在事件对应的数组中的索引。- 如果索引不为 -1(说明该回调函数存在于数组中),使用
splice
方法将其从数组中移除,从而实现取消订阅的功能。
执行结果解释
const eventEmitter = new EventEmitter();// 订阅者的回调函数
const callback1 = (message) => {console.log(`Subscriber 1 received: ${message}`);
};const callback2 = (message) => {console.log(`Subscriber 2 received: ${message}`);
};// 订阅事件
eventEmitter.on('news', callback1);
eventEmitter.on('news', callback2);// 发布事件
eventEmitter.emit('news', 'A new article is published!');
// 输出:
// Subscriber 1 received: A new article is published!
// Subscriber 2 received: A new article is published!// 取消订阅
eventEmitter.off('news', callback1);
eventEmitter.emit('news', 'Another new article!');
// 输出:
// Subscriber 2 received: Another new article!
- 创建一个
EventEmitter
类的实例eventEmitter
。- 定义两个回调函数
callback1
和callback2
,分别表示两个订阅者在收到事件通知时要执行的操作。- 调用
eventEmitter.on
方法,将callback1
和callback2
订阅到'news'
事件上。- 调用
eventEmitter.emit
方法发布'news'
事件,并传递消息'A new article is published!'
。由于callback1
和callback2
都订阅了该事件,所以它们都会被执行,控制台会输出相应的消息。- 调用
eventEmitter.off
方法取消callback1
对'news'
事件的订阅。- 再次调用
eventEmitter.emit
方法发布'news'
事件,并传递消息'Another new article!'
。此时只有callback2
还订阅着该事件,所以只有callback2
会被执行,控制台会输出相应的消息。
三、总结
到此,【设计模式】专栏的篇章已经完结~
文章介绍的是部分常见的设计模式,实际上还有很多设计模式等着大家去学习,后续我有空会补充新的设计模式内容,敬请期待吧~
如果你喜欢这篇文章,留下你的三连+订阅~
关注我,及时获取最新文章消息~