C++中觀察者模式與策略模式的實戰(zhàn)指南
18.1 本章學(xué)習(xí)目標(biāo)與重點(diǎn)
?? 掌握觀察者模式的核心設(shè)計思想、角色劃分及 C++ 實現(xiàn)細(xì)節(jié)(同步/異步、線程安全)
?? 理解策略模式的設(shè)計原則、適用場景及與簡單工廠模式的區(qū)別
?? 能夠結(jié)合實際業(yè)務(wù)場景(如消息通知、算法切換)靈活運(yùn)用兩種模式
?? 解決模式應(yīng)用中的關(guān)鍵問題(如觀察者解注冊、策略動態(tài)切換、循環(huán)依賴)
重點(diǎn):觀察者模式的事件分發(fā)機(jī)制、策略模式的算法封裝邏輯、兩種模式的組合使用技巧
18.2 設(shè)計模式進(jìn)階認(rèn)知:行為型模式的核心價值
在 C++ 開發(fā)中,行為型設(shè)計模式專注于解決“對象之間的交互方式”和“職責(zé)分配”問題,相比創(chuàng)建型模式(如工廠、單例)關(guān)注“對象創(chuàng)建”,行為型模式更側(cè)重“對象協(xié)作”。
18.2.1 為什么需要行為型設(shè)計模式?
實際開發(fā)中,我們常遇到以下交互相關(guān)的問題:
- 一個對象狀態(tài)變化時,需要通知多個其他對象,且通知對象的數(shù)量可能動態(tài)變化(如訂單狀態(tài)更新后,需通知庫存、支付、物流系統(tǒng));
- 一個任務(wù)有多種實現(xiàn)算法,需根據(jù)場景動態(tài)切換(如排序算法可選擇冒泡、快速、歸并排序);
- 交互邏輯分散在多個類中,導(dǎo)致代碼耦合嚴(yán)重,難以維護(hù)和擴(kuò)展;
- 新增交互邏輯時,需修改現(xiàn)有代碼,違反“開放-封閉原則”。
行為型模式通過標(biāo)準(zhǔn)化的交互規(guī)則,將“交互邏輯”與“業(yè)務(wù)邏輯”分離,例如觀察者模式定義“通知-響應(yīng)”規(guī)則,策略模式定義“算法封裝-動態(tài)切換”規(guī)則,從而解決上述問題。
18.2.2 行為型模式的核心設(shè)計原則
行為型模式的設(shè)計始終圍繞以下原則展開,這也是本章兩種模式的核心指導(dǎo)思想:
- 封裝變化:將易變的交互邏輯(如通知規(guī)則、算法實現(xiàn))封裝為獨(dú)立的類,避免影響其他代碼;
- 松耦合協(xié)作:交互的雙方(如觀察者與被觀察者、策略使用者與策略實現(xiàn))僅依賴抽象接口,不依賴具體實現(xiàn);
- 職責(zé)單一:每個類只負(fù)責(zé)一項核心職責(zé)(如觀察者只負(fù)責(zé)響應(yīng)事件,策略類只負(fù)責(zé)實現(xiàn)算法);
- 開閉原則:新增交互邏輯(如新增觀察者、新增策略)時,無需修改現(xiàn)有核心代碼。
18.3 觀察者模式:事件驅(qū)動的通知機(jī)制
觀察者模式(Observer Pattern)又稱發(fā)布-訂閱模式(Publish-Subscribe Pattern),其核心思想是“定義對象間的一對多依賴關(guān)系,當(dāng)一個對象狀態(tài)發(fā)生變化時,所有依賴它的對象都會收到通知并自動更新”。
18.3.1 核心角色與交互流程
1. 核心角色
- 被觀察者(Subject):也稱主題,維護(hù)一個觀察者列表,提供注冊、解注冊觀察者的接口,以及通知所有觀察者的方法;
- 觀察者(Observer):定義接收通知的接口,當(dāng)收到被觀察者的通知時,執(zhí)行相應(yīng)的更新操作;
- 具體被觀察者(ConcreteSubject):被觀察者的具體實現(xiàn),維護(hù)自身狀態(tài),狀態(tài)變化時觸發(fā)通知;
- 具體觀察者(ConcreteObserver):觀察者的具體實現(xiàn),實現(xiàn)更新接口,響應(yīng)被觀察者的通知。
2. 交互流程
① 觀察者通過被觀察者的 RegisterObserver() 方法注冊到被觀察者中;
② 具體被觀察者的狀態(tài)發(fā)生變化;
③ 具體被觀察者調(diào)用 NotifyObservers() 方法,遍歷所有注冊的觀察者;
④ 被觀察者調(diào)用每個觀察者的 Update() 方法,傳遞狀態(tài)變化信息;
⑤ 觀察者通過 Update() 方法接收信息并執(zhí)行相應(yīng)邏輯。
18.3.2 適用場景
- 一個對象的狀態(tài)變化需要觸發(fā)多個其他對象的行為(如訂單狀態(tài)更新、股票價格變動);
- 通知的接收者數(shù)量不固定,需要動態(tài)添加或移除(如系統(tǒng)中的消息訂閱者);
- 觀察者與被觀察者之間無需緊密耦合,希望通過抽象接口進(jìn)行通信(如跨模塊通知)。
18.3.3 基礎(chǔ)實現(xiàn):同步觀察者模式(C++ 示例)
以“氣象站數(shù)據(jù)監(jiān)控系統(tǒng)”為例:氣象站(被觀察者)收集溫度、濕度數(shù)據(jù),當(dāng)數(shù)據(jù)更新時,需通知顯示屏、手機(jī) App、報警器(觀察者)進(jìn)行相應(yīng)展示或報警。
步驟 1:定義觀察者抽象接口
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
// 觀察者抽象接口
class Observer {
public:
// 純虛函數(shù):接收通知并更新(參數(shù):溫度、濕度)
virtual void Update(float temperature, float humidity) = 0;
// 虛析構(gòu)函數(shù):確保子類析構(gòu)時正確釋放資源
virtual ~Observer() {}
};步驟 2:定義被觀察者抽象接口
// 被觀察者抽象接口
class Subject {
public:
// 注冊觀察者
virtual void RegisterObserver(Observer* observer) = 0;
// 解注冊觀察者
virtual void RemoveObserver(Observer* observer) = 0;
// 通知所有觀察者
virtual void NotifyObservers() = 0;
virtual ~Subject() {}
};步驟 3:實現(xiàn)具體被觀察者(氣象站)
// 具體被觀察者:氣象站
class WeatherStation : public Subject {
private:
vector<Observer*> observers; // 存儲注冊的觀察者
float temperature; // 溫度
float humidity; // 濕度
// 檢查觀察者是否已注冊(輔助函數(shù))
bool IsObserverRegistered(Observer* observer) const {
return find(observers.begin(), observers.end(), observer) != observers.end();
}
public:
// 注冊觀察者:添加到列表(避免重復(fù)注冊)
void RegisterObserver(Observer* observer) override {
if (observer == nullptr) {
throw invalid_argument("觀察者不能為空指針!");
}
if (!IsObserverRegistered(observer)) {
observers.push_back(observer);
cout << "觀察者注冊成功:" << typeid(*observer).name() << endl;
} else {
cout << "觀察者已注冊,無需重復(fù)添加:" << typeid(*observer).name() << endl;
}
}
// 解注冊觀察者:從列表中移除
void RemoveObserver(Observer* observer) override {
auto iter = find(observers.begin(), observers.end(), observer);
if (iter != observers.end()) {
observers.erase(iter);
cout << "觀察者解注冊成功:" << typeid(*observer).name() << endl;
} else {
cout << "觀察者未注冊,無法解注冊:" << typeid(*observer).name() << endl;
}
}
// 通知所有觀察者:遍歷列表并調(diào)用 Update 方法
void NotifyObservers() override {
cout << "\n氣象站數(shù)據(jù)更新,開始通知所有觀察者..." << endl;
for (Observer* observer : observers) {
observer->Update(temperature, humidity);
}
}
// 模擬氣象數(shù)據(jù)更新(外部調(diào)用,觸發(fā)通知)
void SetWeatherData(float temp, float humi) {
this->temperature = temp;
this->humidity = humi;
cout << "\n氣象站數(shù)據(jù)更新:溫度=" << temp << "℃,濕度=" << humi << "%" << endl;
NotifyObservers(); // 數(shù)據(jù)更新后自動通知
}
};步驟 4:實現(xiàn)具體觀察者(顯示屏、手機(jī) App、報警器)
// 具體觀察者1:顯示屏(展示實時數(shù)據(jù))
class DisplayScreen : public Observer {
private:
string screenName; // 顯示屏名稱(如"客廳顯示屏")
public:
DisplayScreen(const string& name) : screenName(name) {}
void Update(float temperature, float humidity) override {
cout << "[" << screenName << "] 實時數(shù)據(jù)展示:溫度=" << temperature << "℃,濕度=" << humidity << "%" << endl;
}
};
// 具體觀察者2:手機(jī) App(推送通知)
class MobileApp : public Observer {
private:
string userName; // 用戶名
public:
MobileApp(const string& name) : userName(name) {}
void Update(float temperature, float humidity) override {
cout << "[" << userName << "的手機(jī) App] 推送通知:當(dāng)前溫度" << temperature << "℃,濕度" << humidity << "%" << endl;
}
};
// 具體觀察者3:報警器(濕度超標(biāo)時報警)
class Alarm : public Observer {
private:
float humidityThreshold; // 濕度閾值(超過則報警)
public:
Alarm(float threshold) : humidityThreshold(threshold) {}
void Update(float temperature, float humidity) override {
if (humidity > humidityThreshold) {
cout << "[報警器] 警告!濕度超標(biāo)(當(dāng)前" << humidity << "%,閾值" << humidityThreshold << "%),請及時通風(fēng)!" << endl;
} else {
cout << "[報警器] 濕度正常(當(dāng)前" << humidity << "%),無報警" << endl;
}
}
};步驟 5:客戶端使用示例
int main() {
try {
// 1. 創(chuàng)建被觀察者:氣象站
WeatherStation weatherStation;
// 2. 創(chuàng)建觀察者
Observer* livingRoomScreen = new DisplayScreen("客廳顯示屏");
Observer* bedroomScreen = new DisplayScreen("臥室顯示屏");
Observer* userApp = new MobileApp("張三");
Observer* humidityAlarm = new Alarm(60.0f); // 濕度閾值60%
// 3. 注冊觀察者
weatherStation.RegisterObserver(livingRoomScreen);
weatherStation.RegisterObserver(bedroomScreen);
weatherStation.RegisterObserver(userApp);
weatherStation.RegisterObserver(humidityAlarm);
// 4. 模擬數(shù)據(jù)更新(觸發(fā)第一次通知)
weatherStation.SetWeatherData(25.5f, 55.0f);
// 5. 解注冊臥室顯示屏(不再接收通知)
weatherStation.RemoveObserver(bedroomScreen);
cout << "\n--- 解注冊臥室顯示屏后 ---" << endl;
// 6. 模擬數(shù)據(jù)更新(觸發(fā)第二次通知,臥室顯示屏不再接收)
weatherStation.SetWeatherData(26.8f, 62.0f); // 濕度超標(biāo),報警器會報警
// 7. 釋放資源
delete livingRoomScreen;
delete bedroomScreen;
delete userApp;
delete humidityAlarm;
} catch (const exception& e) {
cout << "錯誤:" << e.what() << endl;
}
return 0;
}運(yùn)行結(jié)果
觀察者注冊成功:class DisplayScreen
觀察者注冊成功:class DisplayScreen
觀察者注冊成功:class MobileApp
觀察者注冊成功:class Alarm氣象站數(shù)據(jù)更新:溫度=25.5℃,濕度=55.0%
氣象站數(shù)據(jù)更新,開始通知所有觀察者...
[客廳顯示屏] 實時數(shù)據(jù)展示:溫度=25.5℃,濕度=55.0%
[臥室顯示屏] 實時數(shù)據(jù)展示:溫度=25.5℃,濕度=55.0%
[張三的手機(jī) App] 推送通知:當(dāng)前溫度25.5℃,濕度55.0%
[報警器] 濕度正常(當(dāng)前55.0%),無報警觀察者解注冊成功:class DisplayScreen
--- 解注冊臥室顯示屏后 ---
氣象站數(shù)據(jù)更新:溫度=26.8℃,濕度=62.0%
氣象站數(shù)據(jù)更新,開始通知所有觀察者...
[客廳顯示屏] 實時數(shù)據(jù)展示:溫度=26.8℃,濕度=62.0%
[張三的手機(jī) App] 推送通知:當(dāng)前溫度26.8℃,濕度62.0%
[報警器] 警告!濕度超標(biāo)(當(dāng)前62.0%,閾值60.0%),請及時通風(fēng)!
18.3.4 進(jìn)階優(yōu)化:線程安全與異步通知
基礎(chǔ)實現(xiàn)是同步通知(被觀察者在主線程中依次調(diào)用觀察者的 Update() 方法),存在兩個問題:
- 線程安全風(fēng)險:若多個線程同時修改被觀察者狀態(tài)或注冊/解注冊觀察者,可能導(dǎo)致列表遍歷異常;
- 性能瓶頸:若某個觀察者的
Update()方法執(zhí)行耗時較長,會阻塞其他觀察者的通知。
優(yōu)化方案 1:線程安全的同步通知(加鎖保護(hù))
使用 std::mutex 保護(hù)觀察者列表的讀寫操作,確保多線程環(huán)境下的安全性:
#include <mutex>
// 線程安全的氣象站(繼承自原 WeatherStation,重寫核心方法)
class ThreadSafeWeatherStation : public Subject {
private:
vector<Observer*> observers;
float temperature;
float humidity;
mutex mtx; // 互斥鎖,保護(hù)觀察者列表
public:
void RegisterObserver(Observer* observer) override {
if (observer == nullptr) {
throw invalid_argument("觀察者不能為空指針!");
}
lock_guard<mutex> lock(mtx); // 自動加鎖/解鎖
auto iter = find(observers.begin(), observers.end(), observer);
if (iter == observers.end()) {
observers.push_back(observer);
cout << "線程安全注冊:" << typeid(*observer).name() << endl;
}
}
void RemoveObserver(Observer* observer) override {
lock_guard<mutex> lock(mtx);
auto iter = find(observers.begin(), observers.end(), observer);
if (iter != observers.end()) {
observers.erase(iter);
cout << "線程安全解注冊:" << typeid(*observer).name() << endl;
}
}
void NotifyObservers() override {
lock_guard<mutex> lock(mtx);
cout << "\n線程安全通知所有觀察者..." << endl;
// 拷貝一份觀察者列表,避免遍歷過程中列表被修改(如解注冊)
vector<Observer*> tempObservers = observers;
lock.unlock(); // 提前解鎖,減少阻塞時間
for (Observer* observer : tempObservers) {
observer->Update(temperature, humidity);
}
}
void SetWeatherData(float temp, float humi) {
lock_guard<mutex> lock(mtx);
this->temperature = temp;
this->humidity = humi;
cout << "\n線程安全氣象站數(shù)據(jù):溫度=" << temp << "℃,濕度=" << humi << "%" << endl;
lock.unlock();
NotifyObservers(); // 通知操作在解鎖后執(zhí)行,避免阻塞寫操作
}
};優(yōu)化方案 2:異步通知(使用線程池)
通過線程池異步執(zhí)行觀察者的 Update() 方法,避免單個觀察者阻塞整個通知流程:
#include <thread>
#include <queue>
#include <condition_variable>
// 簡單線程池(用于異步執(zhí)行任務(wù))
class ThreadPool {
private:
vector<thread> workers; // 工作線程
queue<function<void()>> tasks;// 任務(wù)隊列
mutex mtx; // 保護(hù)任務(wù)隊列
condition_variable cv; // 條件變量,喚醒線程
bool stop; // 線程池停止標(biāo)志
public:
// 構(gòu)造函數(shù):創(chuàng)建n個工作線程
ThreadPool(size_t n) : stop(false) {
for (size_t i = 0; i < n; ++i) {
workers.emplace_back([this]() {
while (true) {
function<void()> task;
{
unique_lock<mutex> lock(this->mtx);
// 等待任務(wù)或停止信號
this->cv.wait(lock, [this]() {
return this->stop || !this->tasks.empty();
});
// 線程池停止且任務(wù)隊列為空,退出線程
if (this->stop && this->tasks.empty()) {
return;
}
// 取出任務(wù)
task = move(this->tasks.front());
this->tasks.pop();
}
// 執(zhí)行任務(wù)
task();
}
});
}
}
// 析構(gòu)函數(shù):停止線程池
~ThreadPool() {
{
unique_lock<mutex> lock(mtx);
stop = true;
}
cv.notify_all(); // 喚醒所有工作線程
for (thread& worker : workers) {
worker.join(); // 等待所有線程完成
}
}
// 添加任務(wù)到線程池
template<typename F>
void Enqueue(F&& f) {
{
unique_lock<mutex> lock(mtx);
if (stop) {
throw runtime_error("線程池已停止,無法添加任務(wù)!");
}
tasks.emplace(forward<F>(f));
}
cv.notify_one(); // 喚醒一個工作線程
}
};
// 異步通知的氣象站
class AsyncWeatherStation : public Subject {
private:
vector<Observer*> observers;
float temperature;
float humidity;
mutex mtx;
ThreadPool pool; // 線程池(2個工作線程)
public:
AsyncWeatherStation() : pool(2) {}
void RegisterObserver(Observer* observer) override {
lock_guard<mutex> lock(mtx);
if (observer && find(observers.begin(), observers.end(), observer) == observers.end()) {
observers.push_back(observer);
}
}
void RemoveObserver(Observer* observer) override {
lock_guard<mutex> lock(mtx);
auto iter = find(observers.begin(), observers.end(), observer);
if (iter != observers.end()) {
observers.erase(iter);
}
}
void NotifyObservers() override {
lock_guard<mutex> lock(mtx);
vector<Observer*> tempObservers = observers;
float temp = temperature;
float humi = humidity;
// 異步執(zhí)行每個觀察者的 Update 方法
for (Observer* observer : tempObservers) {
pool.Enqueue([observer, temp, humi]() {
observer->Update(temp, humi);
});
}
}
void SetWeatherData(float temp, float humi) {
lock_guard<mutex> lock(mtx);
this->temperature = temp;
this->humidity = humi;
cout << "\n異步氣象站數(shù)據(jù)更新:溫度=" << temp << "℃,濕度=" << humi << "%" << endl;
lock.unlock();
NotifyObservers();
}
};異步通知測試代碼
// 模擬耗時的觀察者(如網(wǎng)絡(luò)請求)
class SlowObserver : public Observer {
public:
void Update(float temperature, float humidity) override {
cout << "[耗時觀察者] 開始處理數(shù)據(jù)(模擬網(wǎng)絡(luò)請求)..." << endl;
this_thread::sleep_for(chrono::seconds(2)); // 模擬2秒耗時
cout << "[耗時觀察者] 數(shù)據(jù)處理完成:溫度=" << temperature << "℃" << endl;
}
};
int main() {
AsyncWeatherStation weatherStation;
Observer* fastObserver = new DisplayScreen("快速顯示屏");
Observer* slowObserver = new SlowObserver();
weatherStation.RegisterObserver(fastObserver);
weatherStation.RegisterObserver(slowObserver);
weatherStation.SetWeatherData(24.0f, 58.0f);
cout << "主線程繼續(xù)執(zhí)行其他任務(wù)..." << endl;
// 等待異步任務(wù)完成(實際項目中無需手動等待,線程池會后臺處理)
this_thread::sleep_for(chrono::seconds(3));
delete fastObserver;
delete slowObserver;
return 0;
}異步通知運(yùn)行結(jié)果
異步氣象站數(shù)據(jù)更新:溫度=24.0℃,濕度=58.0%
主線程繼續(xù)執(zhí)行其他任務(wù)...
[快速顯示屏] 實時數(shù)據(jù)展示:溫度=24.0℃,濕度=58.0%
[耗時觀察者] 開始處理數(shù)據(jù)(模擬網(wǎng)絡(luò)請求)...
[耗時觀察者] 數(shù)據(jù)處理完成:溫度=24.0℃
18.3.5 觀察者模式的優(yōu)缺點(diǎn)與避坑指南
優(yōu)點(diǎn)
? 解耦被觀察者與觀察者:兩者僅依賴抽象接口,無需知道對方的具體實現(xiàn);
? 動態(tài)擴(kuò)展:可隨時添加/移除觀察者,無需修改被觀察者代碼,符合“開放-封閉原則”;
? 廣播通知:被觀察者狀態(tài)變化時,自動通知所有注冊的觀察者,無需手動調(diào)用。
缺點(diǎn)
?? 通知順序不確定:同步通知時,觀察者的更新順序與注冊順序一致,但異步通知時順序不可控;
?? 循環(huán)依賴風(fēng)險:若觀察者與被觀察者相互引用,可能導(dǎo)致內(nèi)存泄漏(需使用弱指針 weak_ptr 解決);
?? 性能開銷:若觀察者數(shù)量過多或 Update() 方法耗時,同步通知會導(dǎo)致性能瓶頸(需異步優(yōu)化)。
避坑指南
?? 避免觀察者列表遍歷期間修改列表:注冊/解注冊時需加鎖,或拷貝列表后遍歷(如線程安全實現(xiàn));
?? 處理觀察者空指針:注冊時校驗觀察者指針非空,避免通知時崩潰;
?? 內(nèi)存管理:被觀察者不負(fù)責(zé)銷毀觀察者,需由客戶端統(tǒng)一管理,或使用智能指針(shared_ptr);
?? 避免過度通知:僅在狀態(tài)真正變化時觸發(fā)通知,避免無效更新(如氣象站數(shù)據(jù)未變化時不通知)。
18.4 策略模式:算法的封裝與動態(tài)切換
策略模式(Strategy Pattern)的核心思想是“定義一系列算法,將每個算法封裝起來,并且使它們可以相互替換,讓算法的變化獨(dú)立于使用算法的客戶”。
18.4.1 核心角色與設(shè)計邏輯
1. 核心角色
- 策略抽象(Strategy):定義算法的抽象接口,所有具體策略都需實現(xiàn)該接口;
- 具體策略(ConcreteStrategy):算法的具體實現(xiàn),實現(xiàn)策略抽象接口;
- 上下文(Context):使用策略的角色,持有一個策略對象的引用,提供切換策略的接口,負(fù)責(zé)調(diào)用策略執(zhí)行算法。
2. 設(shè)計邏輯
將易變的算法(如排序算法、支付方式、壓縮算法)封裝為獨(dú)立的策略類,上下文通過依賴注入或動態(tài)設(shè)置的方式使用策略,從而實現(xiàn)“算法切換無需修改上下文代碼”。
18.4.2 適用場景
- 一個任務(wù)有多種實現(xiàn)方式(算法),且需根據(jù)場景動態(tài)切換(如電商支付支持微信、支付寶、銀行卡支付);
- 算法細(xì)節(jié)復(fù)雜,且需要隱藏(如加密算法的實現(xiàn)細(xì)節(jié)不希望暴露給客戶端);
- 避免使用多重
if-else或switch判斷選擇算法(如不同會員等級對應(yīng)不同折扣策略); - 算法需要靈活擴(kuò)展,新增算法時無需修改現(xiàn)有代碼。
18.4.3 基礎(chǔ)實現(xiàn):電商折扣策略系統(tǒng)(C++ 示例)
以“電商平臺折扣系統(tǒng)”為例:不同用戶(普通用戶、VIP用戶、超級VIP用戶)對應(yīng)不同折扣策略,且平臺可能新增“節(jié)日折扣”“優(yōu)惠券折扣”等策略,使用策略模式可靈活擴(kuò)展。
步驟 1:定義策略抽象接口(折扣算法)
#include <iostream>
#include <string>
#include <memory>
using namespace std;
// 策略抽象:折扣策略
class DiscountStrategy {
public:
// 純虛函數(shù):計算折扣后的價格(參數(shù):原價)
virtual float CalculateDiscount(float originalPrice) const = 0;
// 獲取策略名稱(用于日志輸出)
virtual string GetStrategyName() const = 0;
virtual ~DiscountStrategy() {}
};步驟 2:實現(xiàn)具體策略(不同折扣算法)
// 具體策略1:普通用戶策略(無折扣)
class NormalUserStrategy : public DiscountStrategy {
public:
float CalculateDiscount(float originalPrice) const override {
return originalPrice; // 無折扣,原價返回
}
string GetStrategyName() const override {
return "普通用戶無折扣";
}
};
// 具體策略2:VIP用戶策略(9折)
class VIPUserStrategy : public DiscountStrategy {
public:
float CalculateDiscount(float originalPrice) const override {
return originalPrice * 0.9f; // 9折
}
string GetStrategyName() const override {
return "VIP用戶9折";
}
};
// 具體策略3:超級VIP用戶策略(8折+滿1000減200)
class SuperVIPUserStrategy : public DiscountStrategy {
public:
float CalculateDiscount(float originalPrice) const override {
float discountPrice = originalPrice * 0.8f; // 先打8折
if (discountPrice >= 1000) {
discountPrice -= 200; // 滿1000減200
}
return discountPrice;
}
string GetStrategyName() const override {
return "超級VIP用戶8折+滿1000減200";
}
};
// 具體策略4:節(jié)日折扣策略(7折,限節(jié)日使用)
class FestivalDiscountStrategy : public DiscountStrategy {
public:
float CalculateDiscount(float originalPrice) const override {
return originalPrice * 0.7f; // 7折
}
string GetStrategyName() const override {
return "節(jié)日折扣7折";
}
};步驟 3:實現(xiàn)上下文(訂單結(jié)算系統(tǒng))
// 上下文:訂單結(jié)算系統(tǒng)
class OrderSettlement {
private:
// 持有策略對象(使用智能指針,自動管理內(nèi)存)
shared_ptr<DiscountStrategy> strategy;
public:
// 構(gòu)造函數(shù):初始化策略(默認(rèn)普通用戶策略)
OrderSettlement() : strategy(make_shared<NormalUserStrategy>()) {}
// 動態(tài)切換策略(核心方法:支持運(yùn)行時更換策略)
void SetDiscountStrategy(shared_ptr<DiscountStrategy> newStrategy) {
if (newStrategy == nullptr) {
throw invalid_argument("策略不能為空!");
}
strategy = newStrategy;
cout << "折扣策略切換為:" << strategy->GetStrategyName() << endl;
}
// 結(jié)算:調(diào)用當(dāng)前策略計算最終價格
float Settle(float originalPrice) const {
if (originalPrice < 0) {
throw invalid_argument("商品原價不能為負(fù)數(shù)!");
}
float finalPrice = strategy->CalculateDiscount(originalPrice);
cout << "當(dāng)前策略:" << strategy->GetStrategyName() << endl;
cout << "商品原價:" << originalPrice << "元,最終價格:" << finalPrice << "元" << endl;
return finalPrice;
}
};步驟 4:客戶端使用示例
int main() {
try {
// 1. 創(chuàng)建上下文:訂單結(jié)算系統(tǒng)
OrderSettlement settlement;
// 2. 普通用戶結(jié)算(默認(rèn)策略)
cout << "=== 普通用戶購買商品(原價500元)===" << endl;
settlement.Settle(500.0f);
// 3. 切換為VIP用戶策略
cout << "\n=== VIP用戶購買商品(原價800元)===" << endl;
settlement.SetDiscountStrategy(make_shared<VIPUserStrategy>());
settlement.Settle(800.0f);
// 4. 切換為超級VIP用戶策略
cout << "\n=== 超級VIP用戶購買商品(原價1500元)===" << endl;
settlement.SetDiscountStrategy(make_shared<SuperVIPUserStrategy>());
settlement.Settle(1500.0f);
// 5. 切換為節(jié)日折扣策略
cout << "\n=== 節(jié)日期間購買商品(原價2000元)===" << endl;
settlement.SetDiscountStrategy(make_shared<FestivalDiscountStrategy>());
settlement.Settle(2000.0f);
// 6. 新增策略:無需修改結(jié)算系統(tǒng)代碼,直接使用
cout << "\n=== 新增優(yōu)惠券策略(假設(shè)已實現(xiàn))===" << endl;
// 假設(shè)新增 CouponDiscountStrategy,直接通過 SetDiscountStrategy 切換
// settlement.SetDiscountStrategy(make_shared<CouponDiscountStrategy>());
// settlement.Settle(1000.0f);
} catch (const exception& e) {
cout << "結(jié)算失?。? << e.what() << endl;
}
return 0;
}運(yùn)行結(jié)果
=== 普通用戶購買商品(原價500元)===
當(dāng)前策略:普通用戶無折扣
商品原價:500元,最終價格:500元=== VIP用戶購買商品(原價800元)===
折扣策略切換為:VIP用戶9折
當(dāng)前策略:VIP用戶9折
商品原價:800元,最終價格:720元=== 超級VIP用戶購買商品(原價1500元)===
折扣策略切換為:超級VIP用戶8折+滿1000減200
當(dāng)前策略:超級VIP用戶8折+滿1000減200
商品原價:1500元,最終價格:1000元=== 節(jié)日期間購買商品(原價2000元)===
折扣策略切換為:節(jié)日折扣7折
當(dāng)前策略:節(jié)日折扣7折
商品原價:2000元,最終價格:1400元=== 新增優(yōu)惠券策略(假設(shè)已實現(xiàn))===
18.4.4 策略模式與簡單工廠模式的區(qū)別
很多開發(fā)者會混淆策略模式與簡單工廠模式,兩者的核心區(qū)別如下:
| 對比維度 | 策略模式 | 簡單工廠模式 |
|---|---|---|
| 核心目的 | 封裝算法,支持動態(tài)切換 | 封裝對象創(chuàng)建,統(tǒng)一創(chuàng)建邏輯 |
| 關(guān)注點(diǎn) | 算法的“使用”與“切換” | 對象的“創(chuàng)建” |
| 交互方式 | 上下文持有策略對象,主動調(diào)用策略方法 | 客戶端調(diào)用工廠創(chuàng)建對象,自行使用 |
| 擴(kuò)展性 | 新增算法只需新增策略類,無侵入 | 新增產(chǎn)品需修改工廠類(違反開閉原則) |
| 適用場景 | 算法多變、需動態(tài)切換 | 產(chǎn)品類型少、創(chuàng)建邏輯簡單 |
?? 實戰(zhàn)技巧:策略模式可與簡單工廠模式結(jié)合使用!例如,在上下文內(nèi)部通過簡單工廠根據(jù)條件自動選擇策略,無需客戶端手動切換:
// 結(jié)合簡單工廠的上下文
class FactoryStrategySettlement {
private:
shared_ptr<DiscountStrategy> strategy;
// 簡單工廠:根據(jù)用戶類型創(chuàng)建策略
shared_ptr<DiscountStrategy> CreateStrategy(const string& userType) {
if (userType == "normal") {
return make_shared<NormalUserStrategy>();
} else if (userType == "vip") {
return make_shared<VIPUserStrategy>();
} else if (userType == "super_vip") {
return make_shared<SuperVIPUserStrategy>();
} else {
throw invalid_argument("不支持的用戶類型:" + userType);
}
}
public:
// 根據(jù)用戶類型自動選擇策略
FactoryStrategySettlement(const string& userType) {
strategy = CreateStrategy(userType);
}
float Settle(float originalPrice) const {
float finalPrice = strategy->CalculateDiscount(originalPrice);
cout << "用戶類型對應(yīng)策略:" << strategy->GetStrategyName() << endl;
cout << "原價:" << originalPrice << "元,最終價:" << finalPrice << "元" << endl;
return finalPrice;
}
};
// 客戶端使用
int main() {
FactoryStrategySettlement vipSettlement("vip");
vipSettlement.Settle(1000.0f); // 自動使用VIP策略
return 0;
}18.4.5 策略模式的優(yōu)缺點(diǎn)與避坑指南
優(yōu)點(diǎn)
? 算法封裝清晰:每個策略類只負(fù)責(zé)一種算法,職責(zé)單一,便于維護(hù);
? 支持動態(tài)切換:上下文可在運(yùn)行時切換策略,無需重啟程序;
? 符合開閉原則:新增算法只需新增策略類,無需修改上下文或其他策略代碼;
? 避免多重條件判斷:替代 if-else/switch,代碼更簡潔、易擴(kuò)展。
缺點(diǎn)
?? 類數(shù)量增加:每新增一種算法,需新增一個策略類,若算法過多會導(dǎo)致類數(shù)量爆炸;
?? 客戶端需了解策略:客戶端需知道所有策略的存在,才能選擇合適的策略(可通過工廠模式優(yōu)化);
?? 策略間無依賴:若策略之間需要共享數(shù)據(jù),需通過上下文傳遞,增加復(fù)雜度。
避坑指南
?? 策略粒度適中:避免將過于簡單的算法封裝為策略(如僅一行代碼的計算),導(dǎo)致過度設(shè)計;
?? 使用智能指針管理策略:避免策略對象內(nèi)存泄漏,簡化客戶端內(nèi)存管理;
?? 策略不可變:設(shè)計策略類時,盡量使其為無狀態(tài)類(不存儲動態(tài)數(shù)據(jù)),確保線程安全;
?? 復(fù)雜策略組合:若需組合多種策略(如“折扣+優(yōu)惠券”),可結(jié)合裝飾者模式(后續(xù)章節(jié)講解)。
18.5 實戰(zhàn)案例:結(jié)合觀察者模式與策略模式開發(fā)智能物流調(diào)度系統(tǒng)
18.5.1 需求分析
開發(fā)一個智能物流調(diào)度系統(tǒng),核心需求如下:
- 訂單狀態(tài)變化時(如“已支付”“已發(fā)貨”“已簽收”),需通知客戶 App、商家后臺、物流系統(tǒng);
- 調(diào)度算法可動態(tài)切換:根據(jù)訂單類型(普通訂單、加急訂單、大件訂單)選擇不同的調(diào)度策略(如普通調(diào)度、優(yōu)先調(diào)度、大件專用調(diào)度);
- 支持新增訂單狀態(tài)通知對象(如未來新增“保險公司”通知);
- 支持新增調(diào)度策略(如未來新增“冷鏈物流調(diào)度”);
- 多線程環(huán)境下安全運(yùn)行(如同時處理多個訂單狀態(tài)更新)。
18.5.2 設(shè)計思路
- 觀察者模式:處理訂單狀態(tài)通知,訂單(被觀察者)狀態(tài)變化時,通知客戶 App、商家后臺等觀察者;
- 策略模式:處理調(diào)度算法,調(diào)度系統(tǒng)(上下文)根據(jù)訂單類型選擇對應(yīng)的調(diào)度策略;
- 組合設(shè)計:訂單狀態(tài)更新后,觸發(fā)調(diào)度系統(tǒng)執(zhí)行調(diào)度算法,調(diào)度結(jié)果通過觀察者模式通知相關(guān)方。
18.5.3 完整實現(xiàn)代碼
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <mutex>
#include <memory>
#include <thread>
using namespace std;
// -------------------------- 部分1:觀察者模式(訂單狀態(tài)通知) --------------------------
// 觀察者抽象:接收訂單狀態(tài)通知
class OrderStatusObserver {
public:
virtual void OnStatusChanged(const string& orderId, const string& status) = 0;
virtual string GetObserverName() const = 0;
virtual ~OrderStatusObserver() {}
};
// 具體觀察者1:客戶 App
class CustomerAppObserver : public OrderStatusObserver {
public:
void OnStatusChanged(const string& orderId, const string& status) override {
cout << "[客戶 App] 訂單" << orderId << "狀態(tài)更新為:" << status << ",已推送通知給客戶" << endl;
}
string GetObserverName() const override {
return "客戶 App";
}
};
// 具體觀察者2:商家后臺
class MerchantBackendObserver : public OrderStatusObserver {
public:
void OnStatusChanged(const string& orderId, const string& status) override {
cout << "[商家后臺] 訂單" << orderId << "狀態(tài)更新為:" << status << ",已同步至商家管理系統(tǒng)" << endl;
}
string GetObserverName() const override {
return "商家后臺";
}
};
// 具體觀察者3:物流系統(tǒng)
class LogisticsSystemObserver : public OrderStatusObserver {
public:
void OnStatusChanged(const string& orderId, const string& status) override {
cout << "[物流系統(tǒng)] 訂單" << orderId << "狀態(tài)更新為:" << status << ",已觸發(fā)物流調(diào)度" << endl;
}
string GetObserverName() const override {
return "物流系統(tǒng)";
}
};
// 被觀察者:訂單
class Order : public Subject {
private:
string orderId;
string status; // 訂單狀態(tài):"unpaid"(未支付)、"paid"(已支付)、"shipped"(已發(fā)貨)、"received"(已簽收)
vector<OrderStatusObserver*> observers;
mutex mtx;
public:
Order(const string& id) : orderId(id), status("unpaid") {}
// 注冊觀察者(重寫 Subject 接口)
void RegisterObserver(Observer* observer) override {
if (observer == nullptr) return;
OrderStatusObserver* statusObserver = dynamic_cast<OrderStatusObserver*>(observer);
if (statusObserver == nullptr) {
throw invalid_argument("觀察者類型不匹配!");
}
lock_guard<mutex> lock(mtx);
auto iter = find(observers.begin(), observers.end(), statusObserver);
if (iter == observers.end()) {
observers.push_back(statusObserver);
cout << "訂單" << orderId << "注冊觀察者:" << statusObserver->GetObserverName() << endl;
}
}
// 解注冊觀察者(重寫 Subject 接口)
void RemoveObserver(Observer* observer) override {
OrderStatusObserver* statusObserver = dynamic_cast<OrderStatusObserver*>(observer);
if (statusObserver == nullptr) return;
lock_guard<mutex> lock(mtx);
auto iter = find(observers.begin(), observers.end(), statusObserver);
if (iter != observers.end()) {
observers.erase(iter);
cout << "訂單" << orderId << "解注冊觀察者:" << statusObserver->GetObserverName() << endl;
}
}
// 通知觀察者(重寫 Subject 接口)
void NotifyObservers() override {
lock_guard<mutex> lock(mtx);
vector<OrderStatusObserver*> tempObservers = observers;
string tempOrderId = orderId;
string tempStatus = status;
// 異步通知(避免阻塞訂單狀態(tài)更新)
thread([tempObservers, tempOrderId, tempStatus]() {
for (OrderStatusObserver* observer : tempObservers) {
observer->OnStatusChanged(tempOrderId, tempStatus);
}
}).detach();
}
// 更新訂單狀態(tài)(觸發(fā)通知)
void UpdateStatus(const string& newStatus) {
if (newStatus != "unpaid" && newStatus != "paid" && newStatus != "shipped" && newStatus != "received") {
throw invalid_argument("無效的訂單狀態(tài):" + newStatus);
}
lock_guard<mutex> lock(mtx);
if (this->status == newStatus) {
cout << "訂單" << orderId << "狀態(tài)未變化(當(dāng)前:" << newStatus << ")" << endl;
return;
}
this->status = newStatus;
cout << "\n訂單" << orderId << "狀態(tài)更新為:" << newStatus << endl;
NotifyObservers();
}
// 獲取訂單狀態(tài)
string GetStatus() const {
lock_guard<mutex> lock(mtx);
return status;
}
// 獲取訂單ID
string GetOrderId() const {
return orderId;
}
};
// -------------------------- 部分2:策略模式(物流調(diào)度算法) --------------------------
// 策略抽象:調(diào)度策略
class DispatchStrategy {
public:
virtual string Dispatch(const string& orderId, const string& orderType) const = 0;
virtual string GetStrategyName() const = 0;
virtual ~DispatchStrategy() {}
};
// 具體策略1:普通調(diào)度(適用于普通訂單)
class NormalDispatchStrategy : public DispatchStrategy {
public:
string Dispatch(const string& orderId, const string& orderType) const override {
string result = "訂單" + orderId + "(" + orderType + ")使用普通調(diào)度:分配常規(guī)物流車輛,預(yù)計3-5天送達(dá)";
cout << result << endl;
return result;
}
string GetStrategyName() const override {
return "普通調(diào)度策略";
}
};
// 具體策略2:優(yōu)先調(diào)度(適用于加急訂單)
class PriorityDispatchStrategy : public DispatchStrategy {
public:
string Dispatch(const string& orderId, const string& orderType) const override {
string result = "訂單" + orderId + "(" + orderType + ")使用優(yōu)先調(diào)度:分配加急物流車輛,預(yù)計1-2天送達(dá)";
cout << result << endl;
return result;
}
string GetStrategyName() const override {
return "優(yōu)先調(diào)度策略";
}
};
// 具體策略3:大件調(diào)度(適用于大件訂單)
class LargeItemDispatchStrategy : public DispatchStrategy {
public:
string Dispatch(const string& orderId, const string& orderType) const override {
string result = "訂單" + orderId + "(" + orderType + ")使用大件調(diào)度:分配專用大件物流車輛,預(yù)計2-4天送達(dá)";
cout << result << endl;
return result;
}
string GetStrategyName() const override {
return "大件調(diào)度策略";
}
};
// 上下文:物流調(diào)度系統(tǒng)
class LogisticsDispatchSystem {
private:
mutex mtx;
// 策略映射:訂單類型 -> 策略(支持動態(tài)配置)
map<string, shared_ptr<DispatchStrategy>> strategyMap;
public:
// 初始化默認(rèn)策略
LogisticsDispatchSystem() {
strategyMap["normal"] = make_shared<NormalDispatchStrategy>(); // 普通訂單
strategyMap["express"] = make_shared<PriorityDispatchStrategy>(); // 加急訂單
strategyMap["large"] = make_shared<LargeItemDispatchStrategy>(); // 大件訂單
}
// 注冊新策略(支持動態(tài)新增)
void RegisterStrategy(const string& orderType, shared_ptr<DispatchStrategy> strategy) {
if (orderType.empty() || strategy == nullptr) {
throw invalid_argument("訂單類型或策略不能為空!");
}
lock_guard<mutex> lock(mtx);
strategyMap[orderType] = strategy;
cout << "注冊新調(diào)度策略:訂單類型=" << orderType << ",策略=" << strategy->GetStrategyName() << endl;
}
// 執(zhí)行調(diào)度(根據(jù)訂單類型選擇策略)
string DispatchOrder(const string& orderId, const string& orderType) {
lock_guard<mutex> lock(mtx);
auto iter = strategyMap.find(orderType);
if (iter == strategyMap.end()) {
throw invalid_argument("不支持的訂單類型:" + orderType);
}
return iter->second->Dispatch(orderId, orderType);
}
};
// -------------------------- 部分3:系統(tǒng)整合與客戶端測試 --------------------------
// 系統(tǒng)整合:訂單狀態(tài)更新后觸發(fā)調(diào)度
void OnOrderStatusUpdated(const shared_ptr<Order>& order, const shared_ptr<LogisticsDispatchSystem>& dispatchSystem, const string& orderType) {
string status = order->GetStatus();
if (status == "paid") { // 訂單已支付,觸發(fā)調(diào)度
cout << "\n--- 訂單" << order->GetOrderId() << "已支付,開始物流調(diào)度 ---" << endl;
dispatchSystem->DispatchOrder(order->GetOrderId(), orderType);
}
}
int main() {
try {
// 1. 創(chuàng)建物流調(diào)度系統(tǒng)
auto dispatchSystem = make_shared<LogisticsDispatchSystem>();
// 2. 創(chuàng)建觀察者
auto customerApp = make_shared<CustomerAppObserver>();
auto merchantBackend = make_shared<MerchantBackendObserver>();
auto logisticsSystem = make_shared<LogisticsSystemObserver>();
// 3. 創(chuàng)建訂單(普通訂單、加急訂單)
auto normalOrder = make_shared<Order>("ORD20240501001"); // 普通訂單
auto expressOrder = make_shared<Order>("ORD20240501002"); // 加急訂單
// 4. 為訂單注冊觀察者
normalOrder->RegisterObserver(customerApp.get());
normalOrder->RegisterObserver(merchantBackend.get());
normalOrder->RegisterObserver(logisticsSystem.get());
expressOrder->RegisterObserver(customerApp.get());
expressOrder->RegisterObserver(merchantBackend.get());
expressOrder->RegisterObserver(logisticsSystem.get());
// 5. 模擬普通訂單流程:未支付 -> 已支付(觸發(fā)調(diào)度)-> 已發(fā)貨 -> 已簽收
cout << "=== 普通訂單流程 ===" << endl;
normalOrder->UpdateStatus("paid"); // 已支付,觸發(fā)調(diào)度
this_thread::sleep_for(chrono::seconds(1)); // 等待異步通知完成
OnOrderStatusUpdated(normalOrder, dispatchSystem, "normal");
normalOrder->UpdateStatus("shipped"); // 已發(fā)貨
this_thread::sleep_for(chrono::seconds(1));
normalOrder->UpdateStatus("received"); // 已簽收
this_thread::sleep_for(chrono::seconds(1));
// 6. 模擬加急訂單流程
cout << "\n=== 加急訂單流程 ===" << endl;
expressOrder->UpdateStatus("paid"); // 已支付,觸發(fā)調(diào)度
this_thread::sleep_for(chrono::seconds(1));
OnOrderStatusUpdated(expressOrder, dispatchSystem, "express");
// 7. 新增冷鏈物流策略(擴(kuò)展功能)
class ColdChainDispatchStrategy : public DispatchStrategy {
public:
string Dispatch(const string& orderId, const string& orderType) const override {
return "訂單" + orderId + "(" + orderType + ")使用冷鏈調(diào)度:分配冷藏物流車輛,預(yù)計1-2天送達(dá)";
}
string GetStrategyName() const override { return "冷鏈調(diào)度策略"; }
};
dispatchSystem->RegisterStrategy("cold_chain", make_shared<ColdChainDispatchStrategy>());
// 8. 測試新增的冷鏈訂單
auto coldChainOrder = make_shared<Order>("ORD20240501003");
coldChainOrder->RegisterObserver(customerApp.get());
cout << "\n=== 冷鏈訂單流程 ===" << endl;
coldChainOrder->UpdateStatus("paid");
this_thread::sleep_for(chrono::seconds(1));
OnOrderStatusUpdated(coldChainOrder, dispatchSystem, "cold_chain");
} catch (const exception& e) {
cout << "系統(tǒng)錯誤:" << e.what() << endl;
}
return 0;
}18.5.4 代碼說明與運(yùn)行效果
核心設(shè)計亮點(diǎn)
- 觀察者模式負(fù)責(zé)“狀態(tài)通知”:訂單狀態(tài)變化時,異步通知客戶 App、商家后臺等,解耦訂單與通知接收方;
- 策略模式負(fù)責(zé)“算法調(diào)度”:根據(jù)訂單類型動態(tài)選擇調(diào)度策略,支持新增策略(如冷鏈調(diào)度)無侵入擴(kuò)展;
- 組合使用:訂單“已支付”狀態(tài)觸發(fā)物流調(diào)度,實現(xiàn)兩種模式的聯(lián)動,滿足復(fù)雜業(yè)務(wù)流程;
- 線程安全:觀察者注冊/解注冊、訂單狀態(tài)更新、策略調(diào)度均加鎖保護(hù),支持多線程并發(fā)處理。
運(yùn)行結(jié)果(關(guān)鍵片段)
訂單ORD20240501001注冊觀察者:客戶 App
訂單ORD20240501001注冊觀察者:商家后臺
訂單ORD20240501001注冊觀察者:物流系統(tǒng)
...
=== 普通訂單流程 ===訂單ORD20240501001狀態(tài)更新為:paid
[客戶 App] 訂單ORD20240501001狀態(tài)更新為:paid,已推送通知給客戶
[商家后臺] 訂單ORD20240501001狀態(tài)更新為:paid,已同步至商家管理系統(tǒng)
[物流系統(tǒng)] 訂單ORD20240501001狀態(tài)更新為:paid,已觸發(fā)物流調(diào)度--- 訂單ORD20240501001已支付,開始物流調(diào)度 ---
訂單ORD20240501001(normal)使用普通調(diào)度:分配常規(guī)物流車輛,預(yù)計3-5天送達(dá)
...
=== 冷鏈訂單流程 ===
注冊新調(diào)度策略:訂單類型=cold_chain,策略=冷鏈調(diào)度策略訂單ORD20240501003狀態(tài)更新為:paid
[客戶 App] 訂單ORD20240501003狀態(tài)更新為:paid,已推送通知給客戶--- 訂單ORD20240501003已支付,開始物流調(diào)度 ---
訂單ORD20240501003(cold_chain)使用冷鏈調(diào)度:分配冷藏物流車輛,預(yù)計1-2天送達(dá)
18.6 本章總結(jié)
本章重點(diǎn)講解了 C++ 開發(fā)中常用的兩種行為型設(shè)計模式:觀察者模式和策略模式,核心要點(diǎn)總結(jié)如下:
- 觀察者模式:
- 核心價值:實現(xiàn)“一對多”的通知機(jī)制,解耦被觀察者與觀察者;
- 關(guān)鍵實現(xiàn):抽象觀察者接口、被觀察者維護(hù)觀察者列表、通知機(jī)制(同步/異步);
- 進(jìn)階優(yōu)化:線程安全(加鎖)、異步通知(線程池)、避免循環(huán)依賴(弱指針);
- 適用場景:狀態(tài)變化通知、消息訂閱、跨模塊通信。
- 策略模式:
- 核心價值:封裝算法,支持動態(tài)切換,替代多重條件判斷;
- 關(guān)鍵實現(xiàn):策略抽象接口、具體策略類、上下文持有并調(diào)用策略;
- 與工廠模式區(qū)別:策略模式關(guān)注“算法使用與切換”,工廠模式關(guān)注“對象創(chuàng)建”;
- 適用場景:算法多變、動態(tài)切換邏輯(如支付方式、調(diào)度算法、折扣策略)。
- 模式組合技巧:
- 觀察者模式 + 策略模式:狀態(tài)變化觸發(fā)策略執(zhí)行(如訂單支付后觸發(fā)對應(yīng)調(diào)度策略);
- 策略模式 + 簡單工廠:上下文自動選擇策略,簡化客戶端使用;
- 觀察者模式 + 線程池:異步通知提升系統(tǒng)性能,避免阻塞。
- 實戰(zhàn)注意事項:
- 避免過度設(shè)計:簡單場景(如固定幾個觀察者/策略)可簡化實現(xiàn),無需嚴(yán)格遵循模式結(jié)構(gòu);
- 線程安全優(yōu)先:多線程環(huán)境下,需保護(hù)共享資源(如觀察者列表、策略映射);
- 內(nèi)存管理:使用智能指針(
shared_ptr/weak_ptr)避免內(nèi)存泄漏; - 符合開閉原則:新增功能時,優(yōu)先通過擴(kuò)展類實現(xiàn),而非修改現(xiàn)有代碼。
通過本章學(xué)習(xí),你應(yīng)能熟練運(yùn)用觀察者模式和策略模式解決實際開發(fā)中的“交互通知”和“算法切換”問題,結(jié)合兩種模式的組合使用,編寫高內(nèi)聚、低耦合、易擴(kuò)展的 C++ 代碼。后續(xù)章節(jié)將繼續(xù)講解其他行為型設(shè)計模式(如裝飾者模式、適配器模式),進(jìn)一步提升你的代碼設(shè)計能力。
到此這篇關(guān)于C++中觀察者模式與策略模式的實戰(zhàn)指南的文章就介紹到這了,更多相關(guān)C++觀察者模式與策略模式內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
OpenCV中的cv::Mat函數(shù)將數(shù)據(jù)寫入txt文件
這篇文章主要介紹了OpenCVcv::Mat中的數(shù)據(jù)按行列寫入txt文件中,需要的朋友可以參考下2018-05-05
基于C++ bitset常用函數(shù)及運(yùn)算符(詳解)
下面小編就為大家?guī)硪黄贑++ bitset常用函數(shù)及運(yùn)算符(詳解)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-11-11

