跳到主要内容C++ 设计模式实战:观察者与策略模式深度解析 | 极客日志C++算法
C++ 设计模式实战:观察者与策略模式深度解析
C++ 设计模式实战聚焦观察者与策略模式的核心实现与组合应用。文章通过气象站监控与电商折扣系统案例,详解同步/异步通知机制及线程安全优化,对比策略与工厂模式差异。结合智能物流调度系统展示两种模式联动方案,涵盖类结构、内存管理及并发处理技巧,帮助开发者构建高内聚低耦合的 C++ 业务逻辑。
flc1 浏览 C++ 设计模式实战:观察者与策略模式深度解析
本章学习目标与重点
- 掌握观察者模式的核心设计思想、角色划分及 C++ 实现细节(同步/异步、线程安全)
- 理解策略模式的设计原则、适用场景及与简单工厂模式的区别
- 能够结合实际业务场景(如消息通知、算法切换)灵活运用两种模式
- 解决模式应用中的关键问题(如观察者解注册、策略动态切换、循环依赖)
重点:观察者模式的事件分发机制、策略模式的算法封装逻辑、两种模式的组合使用技巧。
设计模式进阶认知:行为型模式的核心价值
在 C++ 开发中,行为型设计模式专注于解决'对象之间的交互方式'和'职责分配'问题。相比创建型模式(如工厂、单例)关注'对象创建',行为型模式更侧重'对象协作'。
为什么需要行为型设计模式?
实际开发中,我们常遇到以下交互相关的问题:
- 一个对象状态变化时,需要通知多个其他对象,且通知对象的数量可能动态变化(如订单状态更新后,需通知库存、支付、物流系统);
- 一个任务有多种实现算法,需根据场景动态切换(如排序算法可选择冒泡、快速、归并排序);
- 交互逻辑分散在多个类中,导致代码耦合严重,难以维护和扩展;
- 新增交互逻辑时,需修改现有代码,违反'开放 - 封闭原则'。
行为型模式通过标准化的交互规则,将'交互逻辑'与'业务逻辑'分离。例如观察者模式定义'通知 - 响应'规则,策略模式定义'算法封装 - 动态切换'规则,从而解决上述问题。
行为型模式的核心设计原则
行为型模式的设计始终围绕以下原则展开,这也是本章两种模式的核心指导思想:
- 封装变化:将易变的交互逻辑(如通知规则、算法实现)封装为独立的类,避免影响其他代码;
- 松耦合协作:交互的双方(如观察者与被观察者、策略使用者与策略实现)仅依赖抽象接口,不依赖具体实现;
- 职责单一:每个类只负责一项核心职责(如观察者只负责响应事件,策略类只负责实现算法);
- 开闭原则:新增交互逻辑(如新增观察者、新增策略)时,无需修改现有核心代码。
观察者模式:事件驱动的通知机制
观察者模式(Observer Pattern)又称发布 - 订阅模式(Publish-Subscribe Pattern),其核心思想是'定义对象间的一对多依赖关系,当一个对象状态发生变化时,所有依赖它的对象都会收到通知并自动更新'。
核心角色与交互流程
1. 核心角色
- 被观察者(Subject):也称主题,维护一个观察者列表,提供注册、解注册观察者的接口,以及通知所有观察者的方法;
- 观察者(Observer):定义接收通知的接口,当收到被观察者的通知时,执行相应的更新操作;
- 具体被观察者(ConcreteSubject):被观察者的具体实现,维护自身状态,状态变化时触发通知;
- 具体观察者(ConcreteObserver):观察者的具体实现,实现更新接口,响应被观察者的通知。
2. 交互流程
- 观察者通过被观察者的
RegisterObserver() 方法注册到被观察者中;
- 具体被观察者的状态发生变化;
- 具体被观察者调用
NotifyObservers() 方法,遍历所有注册的观察者;
- 被观察者调用每个观察者的
Update() 方法,传递状态变化信息;
- 观察者通过
Update() 方法接收信息并执行相应逻辑。
适用场景
- 一个对象的状态变化需要触发多个其他对象的行为(如订单状态更新、股票价格变动);
- 通知的接收者数量不固定,需要动态添加或移除(如系统中的消息订阅者);
- 观察者与被观察者之间无需紧密耦合,希望通过抽象接口进行通信(如跨模块通知)。
基础实现:同步观察者模式(C++ 示例)
以'气象站数据监控系统'为例:气象站(被观察者)收集温度、湿度数据,当数据更新时,需通知显示屏、手机 App、报警器(观察者)进行相应展示或报警。
步骤 1:定义观察者抽象接口
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
class Observer {
public:
virtual void Update(float temperature, float humidity) = 0;
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:实现具体被观察者(气象站)
class WeatherStation : public Subject {
private:
vector<Observer*> observers;
float temperature;
float humidity;
bool IsObserverRegistered(Observer* observer) const {
return find(observers.begin(), observers.end(), observer) != observers.end();
}
public:
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 << "观察者已注册,无需重复添加:" << 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;
}
}
void NotifyObservers() override {
cout << "\n气象站数据更新,开始通知所有观察者..." << endl;
for (Observer* observer : observers) {
observer->Update(temperature, humidity);
}
}
void SetWeatherData(float temp, float humi) {
this->temperature = temp;
this->humidity = humi;
cout << "\n气象站数据更新:温度=" << temp << "℃,湿度=" << humi << "%" << endl;
NotifyObservers();
}
};
步骤 4:实现具体观察者(显示屏、手机 App、报警器)
class DisplayScreen : public Observer {
private:
string screenName;
public:
DisplayScreen(const string& name) : screenName(name) {}
void Update(float temperature, float humidity) override {
cout << "[" << screenName << "] 实时数据展示:温度=" << temperature << "℃,湿度=" << humidity << "%" << endl;
}
};
class MobileApp : public Observer {
private:
string userName;
public:
MobileApp(const string& name) : userName(name) {}
void Update(float temperature, float humidity) override {
cout << "[" << userName << "的手机 App] 推送通知:当前温度" << temperature << "℃,湿度" << humidity << "%" << endl;
}
};
class Alarm : public Observer {
private:
float humidityThreshold;
public:
Alarm(float threshold) : humidityThreshold(threshold) {}
void Update(float temperature, float humidity) override {
if (humidity > humidityThreshold) {
cout << "[报警器] 警告!湿度超标(当前" << humidity << "%,阈值" << humidityThreshold << "%),请及时通风!" << endl;
} else {
cout << "[报警器] 湿度正常(当前" << humidity << "%),无报警" << endl;
}
}
};
步骤 5:客户端使用示例
int main() {
try {
WeatherStation weatherStation;
Observer* livingRoomScreen = new DisplayScreen("客厅显示屏");
Observer* bedroomScreen = new DisplayScreen("卧室显示屏");
Observer* userApp = new MobileApp("张三");
Observer* humidityAlarm = new Alarm(60.0f);
weatherStation.RegisterObserver(livingRoomScreen);
weatherStation.RegisterObserver(bedroomScreen);
weatherStation.RegisterObserver(userApp);
weatherStation.RegisterObserver(humidityAlarm);
weatherStation.SetWeatherData(25.5f, 55.0f);
weatherStation.RemoveObserver(bedroomScreen);
cout << "\n--- 解注册卧室显示屏后 ---" << endl;
weatherStation.SetWeatherData(26.8f, 62.0f);
delete livingRoomScreen;
delete bedroomScreen;
delete userApp;
delete humidityAlarm;
} catch (const exception& e) {
cout << "错误:" << e.what() << endl;
}
return 0;
}
运行结果
观察者注册成功:class DisplayScreen
观察者注册成功:class DisplayScreen
观察者注册成功:class MobileApp
观察者注册成功:class Alarm
气象站数据更新:温度=25.5℃,湿度=55.0%
气象站数据更新,开始通知所有观察者...
[客厅显示屏] 实时数据展示:温度=25.5℃,湿度=55.0%
[卧室显示屏] 实时数据展示:温度=25.5℃,湿度=55.0%
[张三的手机 App] 推送通知:当前温度 25.5℃,湿度 55.0%
[报警器] 湿度正常(当前 55.0%),无报警
观察者解注册成功:class DisplayScreen
--- 解注册卧室显示屏后 ---
气象站数据更新:温度=26.8℃,湿度=62.0%
气象站数据更新,开始通知所有观察者...
[客厅显示屏] 实时数据展示:温度=26.8℃,湿度=62.0%
[张三的手机 App] 推送通知:当前温度 26.8℃,湿度 62.0%
[报警器] 警告!湿度超标(当前 62.0%,阈值 60.0%),请及时通风!
进阶优化:线程安全与异步通知
基础实现是同步通知(被观察者在主线程中依次调用观察者的 Update() 方法),存在两个问题:
- 线程安全风险:若多个线程同时修改被观察者状态或注册/解注册观察者,可能导致列表遍历异常;
- 性能瓶颈:若某个观察者的
Update() 方法执行耗时较长,会阻塞其他观察者的通知。
优化方案 1:线程安全的同步通知(加锁保护)
使用 std::mutex 保护观察者列表的读写操作,确保多线程环境下的安全性:
#include <mutex>
class ThreadSafeWeatherStation : public Subject {
private:
vector<Observer*> observers;
float temperature;
float humidity;
mutex mtx;
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线程安全气象站数据:温度=" << temp << "℃,湿度=" << humi << "%" << endl;
lock.unlock();
NotifyObservers();
}
};
优化方案 2:异步通知(使用线程池)
通过线程池异步执行观察者的 Update() 方法,避免单个观察者阻塞整个通知流程:
#include <thread>
#include <queue>
#include <condition_variable>
class ThreadPool {
private:
vector<thread> workers;
queue<function<void()>> tasks;
mutex mtx;
condition_variable cv;
bool stop;
public:
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);
this->cv.wait(lock, [this]() {
return this->stop || !this->tasks.empty();
});
if (this->stop && this->tasks.empty()) {
return;
}
task = move(this->tasks.front());
this->tasks.pop();
}
task();
}
});
}
}
~ThreadPool() {
{
unique_lock<mutex> lock(mtx);
stop = true;
}
cv.notify_all();
for (thread& worker : workers) {
worker.join();
}
}
template<typename F>
void Enqueue(F&& f) {
{
unique_lock<mutex> lock(mtx);
if (stop) {
throw runtime_error("线程池已停止,无法添加任务!");
}
tasks.emplace(forward<F>(f));
}
cv.notify_one();
}
};
class AsyncWeatherStation : public Subject {
private:
vector<Observer*> observers;
float temperature;
float humidity;
mutex mtx;
ThreadPool pool;
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;
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异步气象站数据更新:温度=" << temp << "℃,湿度=" << humi << "%" << endl;
lock.unlock();
NotifyObservers();
}
};
异步通知测试代码
class SlowObserver : public Observer {
public:
void Update(float temperature, float humidity) override {
cout << "[耗时观察者] 开始处理数据(模拟网络请求)..." << endl;
this_thread::sleep_for(chrono::seconds(2));
cout << "[耗时观察者] 数据处理完成:温度=" << 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 << "主线程继续执行其他任务..." << endl;
this_thread::sleep_for(chrono::seconds(3));
delete fastObserver;
delete slowObserver;
return 0;
}
异步通知运行结果
异步气象站数据更新:温度=24.0℃,湿度=58.0%
主线程继续执行其他任务...
[快速显示屏] 实时数据展示:温度=24.0℃,湿度=58.0%
[耗时观察者] 开始处理数据(模拟网络请求)...
[耗时观察者] 数据处理完成:温度=24.0℃
观察者模式的优缺点与避坑指南
优点
- 解耦被观察者与观察者:两者仅依赖抽象接口,无需知道对方的具体实现;
- 动态扩展:可随时添加/移除观察者,无需修改被观察者代码,符合'开放 - 封闭原则';
- 广播通知:被观察者状态变化时,自动通知所有注册的观察者,无需手动调用。
缺点
- 通知顺序不确定:同步通知时,观察者的更新顺序与注册顺序一致,但异步通知时顺序不可控;
- 循环依赖风险:若观察者与被观察者相互引用,可能导致内存泄漏(需使用弱指针
weak_ptr 解决);
- 性能开销:若观察者数量过多或
Update() 方法耗时,同步通知会导致性能瓶颈(需异步优化)。
避坑指南
- 避免观察者列表遍历期间修改列表:注册/解注册时需加锁,或拷贝列表后遍历(如线程安全实现);
- 处理观察者空指针:注册时校验观察者指针非空,避免通知时崩溃;
- 内存管理:被观察者不负责销毁观察者,需由客户端统一管理,或使用智能指针(
shared_ptr);
- 避免过度通知:仅在状态真正变化时触发通知,避免无效更新(如气象站数据未变化时不通知)。
策略模式:算法的封装与动态切换
策略模式(Strategy Pattern)的核心思想是'定义一系列算法,将每个算法封装起来,并且使它们可以相互替换,让算法的变化独立于使用算法的客户'。
核心角色与设计逻辑
1. 核心角色
- 策略抽象(Strategy):定义算法的抽象接口,所有具体策略都需实现该接口;
- 具体策略(ConcreteStrategy):算法的具体实现,实现策略抽象接口;
- 上下文(Context):使用策略的角色,持有一个策略对象的引用,提供切换策略的接口,负责调用策略执行算法。
2. 设计逻辑
将易变的算法(如排序算法、支付方式、压缩算法)封装为独立的策略类,上下文通过依赖注入或动态设置的方式使用策略,从而实现'算法切换无需修改上下文代码'。
适用场景
- 一个任务有多种实现方式(算法),且需根据场景动态切换(如电商支付支持微信、支付宝、银行卡支付);
- 算法细节复杂,且需要隐藏(如加密算法的实现细节不希望暴露给客户端);
- 避免使用多重
if-else 或 switch 判断选择算法(如不同会员等级对应不同折扣策略);
- 算法需要灵活扩展,新增算法时无需修改现有代码。
基础实现:电商折扣策略系统(C++ 示例)
以'电商平台折扣系统'为例:不同用户(普通用户、VIP 用户、超级 VIP 用户)对应不同折扣策略,且平台可能新增'节日折扣''优惠券折扣'等策略,使用策略模式可灵活扩展。
步骤 1:定义策略抽象接口(折扣算法)
#include <iostream>
#include <string>
#include <memory>
using namespace std;
class DiscountStrategy {
public:
virtual float CalculateDiscount(float originalPrice) const = 0;
virtual string GetStrategyName() const = 0;
virtual ~DiscountStrategy() {}
};
步骤 2:实现具体策略(不同折扣算法)
class NormalUserStrategy : public DiscountStrategy {
public:
float CalculateDiscount(float originalPrice) const override {
return originalPrice;
}
string GetStrategyName() const override {
return "普通用户无折扣";
}
};
class VIPUserStrategy : public DiscountStrategy {
public:
float CalculateDiscount(float originalPrice) const override {
return originalPrice * 0.9f;
}
string GetStrategyName() const override {
return "VIP 用户 9 折";
}
};
class SuperVIPUserStrategy : public DiscountStrategy {
public:
float CalculateDiscount(float originalPrice) const override {
float discountPrice = originalPrice * 0.8f;
if (discountPrice >= 1000) {
discountPrice -= 200;
}
return discountPrice;
}
string GetStrategyName() const override {
return "超级 VIP 用户 8 折 + 满 1000 减 200";
}
};
class FestivalDiscountStrategy : public DiscountStrategy {
public:
float CalculateDiscount(float originalPrice) const override {
return originalPrice * 0.7f;
}
string GetStrategyName() const override {
return "节日折扣 7 折";
}
};
步骤 3:实现上下文(订单结算系统)
class OrderSettlement {
private:
shared_ptr<DiscountStrategy> strategy;
public:
OrderSettlement() : strategy(make_shared<NormalUserStrategy>()) {}
void SetDiscountStrategy(shared_ptr<DiscountStrategy> newStrategy) {
if (newStrategy == nullptr) {
throw invalid_argument("策略不能为空!");
}
strategy = newStrategy;
cout << "折扣策略切换为:" << strategy->GetStrategyName() << endl;
}
float Settle(float originalPrice) const {
if (originalPrice < 0) {
throw invalid_argument("商品原价不能为负数!");
}
float finalPrice = strategy->CalculateDiscount(originalPrice);
cout << "当前策略:" << strategy->GetStrategyName() << endl;
cout << "商品原价:" << originalPrice << "元,最终价格:" << finalPrice << "元" << endl;
return finalPrice;
}
};
步骤 4:客户端使用示例
int main() {
try {
OrderSettlement settlement;
cout << "=== 普通用户购买商品(原价 500 元)===" << endl;
settlement.Settle(500.0f);
cout << "\n=== VIP 用户购买商品(原价 800 元)===" << endl;
settlement.SetDiscountStrategy(make_shared<VIPUserStrategy>());
settlement.Settle(800.0f);
cout << "\n=== 超级 VIP 用户购买商品(原价 1500 元)===" << endl;
settlement.SetDiscountStrategy(make_shared<SuperVIPUserStrategy>());
settlement.Settle(1500.0f);
cout << "\n=== 节日期间购买商品(原价 2000 元)===" << endl;
settlement.SetDiscountStrategy(make_shared<FestivalDiscountStrategy>());
settlement.Settle(2000.0f);
cout << "\n=== 新增优惠券策略(假设已实现)===" << endl;
} catch (const exception& e) {
cout << "结算失败:" << e.what() << endl;
}
return 0;
}
运行结果
当前策略:普通用户无折扣
商品原价:500 元,最终价格:500 元
折扣策略切换为:VIP 用户 9 折
当前策略:VIP 用户 9 折
商品原价:800 元,最终价格:720 元
折扣策略切换为:超级 VIP 用户 8 折 + 满 1000 减 200
当前策略:超级 VIP 用户 8 折 + 满 1000 减 200
商品原价:1500 元,最终价格:1000 元
折扣策略切换为:节日折扣 7 折
当前策略:节日折扣 7 折
商品原价:2000 元,最终价格:1400 元
策略模式与简单工厂模式的区别
很多开发者会混淆策略模式与简单工厂模式,两者的核心区别如下:
| 对比维度 | 策略模式 | 简单工厂模式 |
|---|
| 核心目的 | 封装算法,支持动态切换 | 封装对象创建,统一创建逻辑 |
| 关注点 | 算法的'使用'与'切换' | 对象的'创建' |
| 交互方式 | 上下文持有策略对象,主动调用策略方法 | 客户端调用工厂创建对象,自行使用 |
| 扩展性 | 新增算法只需新增策略类,无侵入 | 新增产品需修改工厂类(违反开闭原则) |
| 适用场景 | 算法多变、需动态切换 | 产品类型少、创建逻辑简单 |
实战技巧:策略模式可与简单工厂模式结合使用!例如,在上下文内部通过简单工厂根据条件自动选择策略,无需客户端手动切换:
class FactoryStrategySettlement {
private:
shared_ptr<DiscountStrategy> strategy;
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:
FactoryStrategySettlement(const string& userType) {
strategy = CreateStrategy(userType);
}
float Settle(float originalPrice) const {
float finalPrice = strategy->CalculateDiscount(originalPrice);
cout << "用户类型对应策略:" << strategy->GetStrategyName() << endl;
cout << "原价:" << originalPrice << "元,最终价:" << finalPrice << "元" << endl;
return finalPrice;
}
};
int main() {
FactoryStrategySettlement vipSettlement("vip");
vipSettlement.Settle(1000.0f);
return 0;
}
策略模式的优缺点与避坑指南
优点
- 算法封装清晰:每个策略类只负责一种算法,职责单一,便于维护;
- 支持动态切换:上下文可在运行时切换策略,无需重启程序;
- 符合开闭原则:新增算法只需新增策略类,无需修改上下文或其他策略代码;
- 避免多重条件判断:替代
if-else/switch,代码更简洁、易扩展。
缺点
- 类数量增加:每新增一种算法,需新增一个策略类,若算法过多会导致类数量爆炸;
- 客户端需了解策略:客户端需知道所有策略的存在,才能选择合适的策略(可通过工厂模式优化);
- 策略间无依赖:若策略之间需要共享数据,需通过上下文传递,增加复杂度。
避坑指南
- 策略粒度适中:避免将过于简单的算法封装为策略(如仅一行代码的计算),导致过度设计;
- 使用智能指针管理策略:避免策略对象内存泄漏,简化客户端内存管理;
- 策略不可变:设计策略类时,尽量使其为无状态类(不存储动态数据),确保线程安全;
- 复杂策略组合:若需组合多种策略(如'折扣 + 优惠券'),可结合装饰者模式(后续章节讲解)。
实战案例:结合观察者模式与策略模式开发智能物流调度系统
需求分析
- 订单状态变化时(如'已支付''已发货''已签收'),需通知客户 App、商家后台、物流系统;
- 调度算法可动态切换:根据订单类型(普通订单、加急订单、大件订单)选择不同的调度策略(如普通调度、优先调度、大件专用调度);
- 支持新增订单状态通知对象(如未来新增'保险公司'通知);
- 支持新增调度策略(如未来新增'冷链物流调度');
- 多线程环境下安全运行(如同时处理多个订单状态更新)。
设计思路
- 观察者模式:处理订单状态通知,订单(被观察者)状态变化时,通知客户 App、商家后台等观察者;
- 策略模式:处理调度算法,调度系统(上下文)根据订单类型选择对应的调度策略;
- 组合设计:订单状态更新后,触发调度系统执行调度算法,调度结果通过观察者模式通知相关方。
完整实现代码
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <mutex>
#include <memory>
#include <thread>
using namespace std;
class OrderStatusObserver {
public:
virtual void OnStatusChanged(const string& orderId, const string& status) = 0;
virtual string GetObserverName() const = 0;
virtual ~OrderStatusObserver() {}
};
class CustomerAppObserver : public OrderStatusObserver {
public:
void OnStatusChanged(const string& orderId, const string& status) override {
cout << "[客户 App] 订单" << orderId << "状态更新为:" << status << ",已推送通知给客户" << endl;
}
string GetObserverName() const override { return "客户 App"; }
};
class MerchantBackendObserver : public OrderStatusObserver {
public:
void OnStatusChanged(const string& orderId, const string& status) override {
cout << "[商家后台] 订单" << orderId << "状态更新为:" << status << ",已同步至商家管理系统" << endl;
}
string GetObserverName() const override { return "商家后台"; }
};
class LogisticsSystemObserver : public OrderStatusObserver {
public:
void OnStatusChanged(const string& orderId, const string& status) override {
cout << "[物流系统] 订单" << orderId << "状态更新为:" << status << ",已触发物流调度" << endl;
}
string GetObserverName() const override { return "物流系统"; }
};
class Order : public Subject {
private:
string orderId;
string status;
vector<OrderStatusObserver*> observers;
mutex mtx;
public:
Order(const string& id) : orderId(id), status("unpaid") {}
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;
}
}
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;
}
}
void NotifyObservers() override {
lock_guard<mutex> lock(mtx);
vector<OrderStatusObserver*> tempObservers = observers;
string tempOrderId = orderId;
string tempStatus = status;
thread([tempObservers, tempOrderId, tempStatus]() {
for (OrderStatusObserver* observer : tempObservers) {
observer->OnStatusChanged(tempOrderId, tempStatus);
}
}).detach();
}
void UpdateStatus(const string& newStatus) {
if (newStatus != "unpaid" && newStatus != "paid" && newStatus != "shipped" && newStatus != "received") {
throw invalid_argument("无效的订单状态:" + newStatus);
}
lock_guard<mutex> lock(mtx);
if (this->status == newStatus) {
cout << "订单" << orderId << "状态未变化(当前:" << newStatus << ")" << endl;
return;
}
this->status = newStatus;
cout << "\n订单" << orderId << "状态更新为:" << newStatus << endl;
NotifyObservers();
}
string GetStatus() const {
lock_guard<mutex> lock(mtx);
return status;
}
string GetOrderId() const { return orderId; }
};
class DispatchStrategy {
public:
virtual string Dispatch(const string& orderId, const string& orderType) const = 0;
virtual string GetStrategyName() const = 0;
virtual ~DispatchStrategy() {}
};
class NormalDispatchStrategy : public DispatchStrategy {
public:
string Dispatch(const string& orderId, const string& orderType) const override {
string result = "订单" + orderId + "(" + orderType + ")使用普通调度:分配常规物流车辆,预计 3-5 天送达";
cout << result << endl;
return result;
}
string GetStrategyName() const override { return "普通调度策略"; }
};
class PriorityDispatchStrategy : public DispatchStrategy {
public:
string Dispatch(const string& orderId, const string& orderType) const override {
string result = "订单" + orderId + "(" + orderType + ")使用优先调度:分配加急物流车辆,预计 1-2 天送达";
cout << result << endl;
return result;
}
string GetStrategyName() const override { return "优先调度策略"; }
};
class LargeItemDispatchStrategy : public DispatchStrategy {
public:
string Dispatch(const string& orderId, const string& orderType) const override {
string result = "订单" + orderId + "(" + orderType + ")使用大件调度:分配专用大件物流车辆,预计 2-4 天送达";
cout << result << endl;
return result;
}
string GetStrategyName() const override { return "大件调度策略"; }
};
class LogisticsDispatchSystem {
private:
mutex mtx;
map<string, shared_ptr<DispatchStrategy>> strategyMap;
public:
LogisticsDispatchSystem() {
strategyMap["normal"] = make_shared<NormalDispatchStrategy>();
strategyMap["express"] = make_shared<PriorityDispatchStrategy>();
strategyMap["large"] = make_shared<LargeItemDispatchStrategy>();
}
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 << "注册新调度策略:订单类型=" << orderType << ",策略=" << strategy->GetStrategyName() << endl;
}
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);
}
};
void OnOrderStatusUpdated(const shared_ptr<Order>& order, const shared_ptr<LogisticsDispatchSystem>& dispatchSystem, const string& orderType) {
string status = order->GetStatus();
if (status == "paid") {
cout << "\n--- 订单" << order->GetOrderId() << "已支付,开始物流调度 ---" << endl;
dispatchSystem->DispatchOrder(order->GetOrderId(), orderType);
}
}
int main() {
try {
auto dispatchSystem = make_shared<LogisticsDispatchSystem>();
auto customerApp = make_shared<CustomerAppObserver>();
auto merchantBackend = make_shared<MerchantBackendObserver>();
auto logisticsSystem = make_shared<LogisticsSystemObserver>();
auto normalOrder = make_shared<Order>("ORD20240501001");
auto expressOrder = make_shared<Order>("ORD20240501002");
normalOrder->RegisterObserver(customerApp.get());
normalOrder->RegisterObserver(merchantBackend.get());
normalOrder->RegisterObserver(logisticsSystem.get());
expressOrder->RegisterObserver(customerApp.get());
expressOrder->RegisterObserver(merchantBackend.get());
expressOrder->RegisterObserver(logisticsSystem.get());
cout << "=== 普通订单流程 ===" << endl;
normalOrder->UpdateStatus("paid");
this_thread::sleep_for(chrono::seconds(1));
OnOrderStatusUpdated(normalOrder, dispatchSystem, "normal");
normalOrder->UpdateStatus("shipped");
this_thread::sleep_for(chrono::seconds(1));
normalOrder->UpdateStatus("received");
this_thread::sleep_for(chrono::seconds(1));
cout << "\n=== 加急订单流程 ===" << endl;
expressOrder->UpdateStatus("paid");
this_thread::sleep_for(chrono::seconds(1));
OnOrderStatusUpdated(expressOrder, dispatchSystem, "express");
class ColdChainDispatchStrategy : public DispatchStrategy {
public:
string Dispatch(const string& orderId, const string& orderType) const override {
return "订单" + orderId + "(" + orderType + ")使用冷链调度:分配冷藏物流车辆,预计 1-2 天送达";
}
string GetStrategyName() const override { return "冷链调度策略"; }
};
dispatchSystem->RegisterStrategy("cold_chain", make_shared<ColdChainDispatchStrategy>());
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 << "系统错误:" << e.what() << endl;
}
return 0;
}
代码说明与运行效果
核心设计亮点
- 观察者模式负责'状态通知':订单状态变化时,异步通知客户 App、商家后台等,解耦订单与通知接收方;
- 策略模式负责'算法调度':根据订单类型动态选择调度策略,支持新增策略(如冷链调度)无侵入扩展;
- 组合使用:订单'已支付'状态触发物流调度,实现两种模式的联动,满足复杂业务流程;
- 线程安全:观察者注册/解注册、订单状态更新、策略调度均加锁保护,支持多线程并发处理。
运行结果(关键片段)
订单 ORD20240501001 注册观察者:客户 App
订单 ORD20240501001 注册观察者:商家后台
订单 ORD20240501001 注册观察者:物流系统
...
=== 普通订单流程 ===
订单 ORD20240501001 状态更新为:paid
[客户 App] 订单 ORD20240501001 状态更新为:paid,已推送通知给客户
[商家后台] 订单 ORD20240501001 状态更新为:paid,已同步至商家管理系统
[物流系统] 订单 ORD20240501001 状态更新为:paid,已触发物流调度
--- 订单 ORD20240501001 已支付,开始物流调度 ---
订单 ORD20240501001(normal)使用普通调度:分配常规物流车辆,预计 3-5 天送达
...
=== 冷链订单流程 ===
注册新调度策略:订单类型=cold_chain,策略=冷链调度策略
订单 ORD20240501003 状态更新为:paid
[客户 App] 订单 ORD20240501003 状态更新为:paid,已推送通知给客户
--- 订单 ORD20240501003 已支付,开始物流调度 ---
订单 ORD20240501003(cold_chain)使用冷链调度:分配冷藏物流车辆,预计 1-2 天送达
本章总结
本章重点讲解了 C++ 开发中常用的两种行为型设计模式:观察者模式和策略模式,核心要点总结如下:
- 观察者模式:
- 核心价值:实现'一对多'的通知机制,解耦被观察者与观察者;
- 关键实现:抽象观察者接口、被观察者维护观察者列表、通知机制(同步/异步);
- 进阶优化:线程安全(加锁)、异步通知(线程池)、避免循环依赖(弱指针);
- 适用场景:状态变化通知、消息订阅、跨模块通信。
- 策略模式:
- 核心价值:封装算法,支持动态切换,替代多重条件判断;
- 关键实现:策略抽象接口、具体策略类、上下文持有并调用策略;
- 与工厂模式区别:策略模式关注'算法使用与切换',工厂模式关注'对象创建';
- 适用场景:算法多变、动态切换逻辑(如支付方式、调度算法、折扣策略)。
- 模式组合技巧:
- 观察者模式 + 策略模式:状态变化触发策略执行(如订单支付后触发对应调度策略);
- 策略模式 + 简单工厂:上下文自动选择策略,简化客户端使用;
- 观察者模式 + 线程池:异步通知提升系统性能,避免阻塞。
- 实战注意事项:
- 避免过度设计:简单场景(如固定几个观察者/策略)可简化实现,无需严格遵循模式结构;
- 线程安全优先:多线程环境下,需保护共享资源(如观察者列表、策略映射);
- 内存管理:使用智能指针(
shared_ptr/weak_ptr)避免内存泄漏;
- 符合开闭原则:新增功能时,优先通过扩展类实现,而非修改现有代码。
通过本章学习,你应能熟练运用观察者模式和策略模式解决实际开发中的'交互通知'和'算法切换'问题,结合两种模式的组合使用,编写高内聚、低耦合、易扩展的 C++ 代码。后续章节将继续讲解其他行为型设计模式(如装饰者模式、适配器模式),进一步提升你的代码设计能力。
相关免费在线工具
- 加密/解密文本
使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
- Gemini 图片去水印
基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online
- Base64 字符串编码/解码
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
- Base64 文件转换器
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
- Markdown转HTML
将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online
- HTML转Markdown
将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online