C++设计模式之观察者模式:以家具生产为例
在日常家具生产场景中,我们经常会遇到这样的情况:家具工厂生产出新款沙发、衣柜等产品后,需要及时通知经销商备货、零售商上架、意向客户了解详情。如果工厂逐一给每个相关方打电话通知,不仅效率低下,后续新增家装公司等合作方时,还需要修改工厂的通知逻辑。这种场景下,观察者模式就能派上大用场——它能建立一种"工厂(被观察者)状态变化,所有关联方(观察者)自动知情"的高效联动机制。
一、观察者模式核心概念
观察者模式是一种行为型设计模式,其核心是定义对象间的一对多依赖关系:当"被观察者"(也叫主题)的状态发生改变时,所有依赖它的"观察者"都会收到通知并自动更新。这种模式的优势在于解耦被观察者和观察者——双方无需知道对方的具体实现,只需通过统一接口交互,新增或删除观察者时无需修改被观察者代码。
结合家具生产场景,各角色对应关系如下:
-
被观察者(主题):家具工厂,负责生产家具并维护观察者列表,状态变化(如新款家具下线、产能调整)时通知所有观察者。
-
观察者:经销商、零售商、意向客户等,需要关注工厂状态变化,收到通知后执行对应操作(备货、上架、咨询)。
-
核心约定:工厂提供"注册观察者""移除观察者""通知观察者"的统一接口;观察者提供"接收通知并处理"的统一接口。
二、观察者模式结构拆解(家具生产场景)
观察者模式通常包含4个核心组件,结合家具生产场景的具体实现如下:
-
抽象观察者(Abstract Observer):定义观察者的统一接口,包含一个"更新通知"方法。对应场景中的"家具关注者"接口,所有需要关注工厂动态的角色都要实现该接口。
-
具体观察者(Concrete Observer):实现抽象观察者接口,定义收到通知后的具体操作。对应场景中的经销商、零售商、意向客户。
-
抽象被观察者(Abstract Subject):定义被观察者的统一接口,包含"添加观察者""移除观察者""通知所有观察者"的方法,以及维护观察者列表和自身状态的属性。对应场景中的"家具生产主体"接口。
-
具体被观察者(Concrete Subject):实现抽象被观察者接口,维护自身状态(如当前生产的家具类型、生产状态),当状态变化时调用通知方法。对应场景中的"具体家具工厂"。
三、C++代码实现(家具生产场景)
下面通过C++代码实现上述场景,代码中包含完整的接口定义、具体类实现、客户端测试逻辑,并添加详细注释说明关键逻辑。
#include <iostream>
#include <vector>
#include <string>
// 提前声明抽象被观察者,解决观察者与被观察者的循环依赖问题
class AbstractFurnitureFactory;
// 1. 抽象观察者:家具关注者(所有关注工厂动态的角色都要实现)
class AbstractObserver {
public:
// 纯虚函数:接收通知的核心方法,参数为通知内容(家具信息、生产状态等)
virtual void update(const std::string& furnitureInfo, const std::string& status) = 0;
// 虚析构:确保子类析构时能正确调用
virtual ~AbstractObserver() {}
};
// 2. 抽象被观察者:家具生产主体(家具工厂的统一接口)
class AbstractFurnitureFactory {
public:
// 虚析构
virtual ~AbstractFurnitureFactory() {}
// 注册观察者(添加关注者)
virtual void attach(AbstractObserver* observer) = 0;
// 移除观察者(取消关注)
virtual void detach(AbstractObserver* observer) = 0;
// 通知所有观察者(状态变化时调用)
virtual void notify() = 0;
// 设置生产状态(触发通知的条件)
virtual void setProductionStatus(const std::string& furnitureInfo, const std::string& status) = 0;
};
// 3. 具体被观察者:实木家具工厂(实际生产家具的主体)
class SolidWoodFurnitureFactory : public AbstractFurnitureFactory {
private:
// 维护观察者列表(关注工厂的所有角色)
std::vector<AbstractObserver*> observers;
// 工厂当前生产的家具信息(状态1)
std::string currentFurniture;
// 工厂当前生产状态(状态2:如"已下线""生产中""缺货")
std::string currentStatus;
public:
// 注册观察者:将观察者加入列表
void attach(AbstractObserver* observer) override {
observers.push_back(observer);
std::cout << "新增关注者成功!" << std::endl;
}
// 移除观察者:将观察者从列表中删除
void detach(AbstractObserver* observer) override {
for (auto it = observers.begin(); it != observers.end(); ++it) {
if (*it == observer) {
observers.erase(it);
std::cout << "移除关注者成功!" << std::endl;
return;
}
}
std::cout << "未找到该关注者!" << std::endl;
}
// 通知所有观察者:遍历列表,调用每个观察者的update方法
void notify() override {
std::cout << "\n=== 实木家具工厂发布通知 ===" << std::endl;
for (auto observer : observers) {
// 将当前状态传递给观察者
observer->update(currentFurniture, currentStatus);
}
}
// 设置生产状态:修改状态后自动触发通知
void setProductionStatus(const std::string& furnitureInfo, const std::string& status) override {
currentFurniture = furnitureInfo;
currentStatus = status;
// 状态变化,通知所有观察者
notify();
}
};
// 4. 具体观察者1:家具经销商(收到通知后备货)
class FurnitureDealer : public AbstractObserver {
private:
// 经销商名称(区分不同观察者)
std::string dealerName;
public:
FurnitureDealer(const std::string& name) : dealerName(name) {}
// 实现update方法:经销商收到通知后的操作
void update(const std::string& furnitureInfo, const std::string& status) override {
if (status == "已下线") {
std::cout << "经销商【" << dealerName << "】:收到通知!"
<< furnitureInfo << "已生产完成,立即安排备货100套!" << std::endl;
} else if (status == "缺货") {
std::cout << "经销商【" << dealerName << "】:收到通知!"
<< furnitureInfo << "缺货,暂停接单并催促工厂生产!" << std::endl;
}
}
};
// 5. 具体观察者2:家具零售商(收到通知后上架)
class FurnitureRetailer : public AbstractObserver {
private:
// 零售商名称
std::string retailerName;
public:
FurnitureRetailer(const std::string& name) : retailerName(name) {}
// 实现update方法:零售商收到通知后的操作
void update(const std::string& furnitureInfo, const std::string& status) override {
if (status == "已下线") {
std::cout << "零售商【" << retailerName << "】:收到通知!"
<< furnitureInfo << "已到店,立即布置展台并上架销售!" << std::endl;
} else if (status == "缺货") {
std::cout << "零售商【" << retailerName << "】:收到通知!"
<< furnitureInfo << "缺货,立即更新库存标识为'缺货'!" << std::endl;
}
}
};
// 6. 具体观察者3:意向客户(收到通知后咨询)
class IntendedCustomer : public AbstractObserver {
private:
// 客户姓名
std::string customerName;
public:
IntendedCustomer(const std::string& name) : customerName(name) {}
// 实现update方法:客户收到通知后的操作
void update(const std::string& furnitureInfo, const std::string& status) override {
if (status == "已下线") {
std::cout << "客户【" << customerName << "】:收到通知!"
<< furnitureInfo << "已生产完成,立即联系门店咨询价格和配送!" << std::endl;
} else if (status == "生产中") {
std::cout << "客户【" << customerName << "】:收到通知!"
<< furnitureInfo << "正在生产中,等待后续通知!" << std::endl;
}
}
};
// 客户端测试:模拟家具生产流程中的通知场景
int main() {
// 1. 创建被观察者:实木家具工厂
AbstractFurnitureFactory* factory = new SolidWoodFurnitureFactory();
// 2. 创建具体观察者:经销商、零售商、客户
AbstractObserver* dealer = new FurnitureDealer("诚信家具批发部");
AbstractObserver* retailer = new FurnitureRetailer("宜家家居门店");
AbstractObserver* customer1 = new IntendedCustomer("张三");
AbstractObserver* customer2 = new IntendedCustomer("李四");
// 3. 注册观察者:关注工厂动态
factory->attach(dealer);
factory->attach(retailer);
factory->attach(customer1);
// 4. 工厂状态变化1:新款实木沙发下线(触发通知)
factory->setProductionStatus("新款北欧实木沙发(三人位)", "已下线");
// 5. 移除观察者:客户李四取消关注(先注册再移除,测试移除功能)
factory->attach(customer2);
factory->detach(customer2);
// 6. 工厂状态变化2:实木沙发缺货(触发通知)
factory->setProductionStatus("新款北欧实木沙发(三人位)", "缺货");
// 7. 工厂状态变化3:实木衣柜生产中(触发通知)
factory->setProductionStatus("中式实木衣柜(2米高)", "生产中");
// 8. 释放资源
delete customer2;
delete customer1;
delete retailer;
delete dealer;
delete factory;
return 0;
}
四、代码分析
-
解耦特性:工厂(被观察者)无需知道具体是哪个经销商、客户在关注,只需调用
notify方法即可通知所有观察者;新增"家装公司"观察者时,只需实现AbstractObserver接口并注册到工厂,无需修改工厂代码。 -
状态联动:当工厂调用
setProductionStatus修改状态后,会自动触发notify方法,所有注册的观察者都会收到更新,避免了人工逐一通知的繁琐。 -
灵活控制:通过
attach和detach方法,观察者可以自由关注或取消关注工厂,符合实际场景中"客户取消预约""经销商终止合作"等需求。
五、观察者模式的适用场景总结
结合本次家具生产的例子,当业务中存在以下场景时,优先考虑观察者模式:
-
一个对象状态变化需要联动多个对象更新,如工厂生产状态变化联动经销商、零售商、客户;
-
需要解耦被通知者和通知者,避免两者直接依赖,如工厂无需知道客户的具体信息,只需通过统一接口通知;
-
需要动态添加或删除被通知者,如新增家装公司关注工厂、客户取消关注。
在C++实际开发中,观察者模式还常用于GUI界面(如按钮点击联动多个组件更新)、日志系统(如日志级别变化联动多个输出端)等场景,是一种实用性极高的设计模式。
更多推荐

所有评论(0)