前言
前面我們介紹完創建型模式和創建型模式,這篇介紹最后的行為型模式,也是【設計模式】專欄的最后一篇。
一、概述
行為型模式主要用于處理對象之間的交互和職責分配,以實現更靈活的行為和更好的協作。
二、常見的行為型模式
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
?會被執行,控制臺會輸出相應的消息。
三、總結
?到此,【設計模式】專欄的篇章已經完結~
文章介紹的是部分常見的設計模式,實際上還有很多設計模式等著大家去學習,后續我有空會補充新的設計模式內容,敬請期待吧~
如果你喜歡這篇文章,留下你的三連+訂閱~
關注我,及時獲取最新文章消息~