在日常家具生产场景中,我们经常会遇到这样的情况:家具工厂生产出新款沙发、衣柜等产品后,需要及时通知经销商备货、零售商上架、意向客户了解详情。如果工厂逐一给每个相关方打电话通知,不仅效率低下,后续新增家装公司等合作方时,还需要修改工厂的通知逻辑。这种场景下,观察者模式就能派上大用场——它能建立一种"工厂(被观察者)状态变化,所有关联方(观察者)自动知情"的高效联动机制。

一、观察者模式核心概念

观察者模式是一种行为型设计模式,其核心是定义对象间的一对多依赖关系:当"被观察者"(也叫主题)的状态发生改变时,所有依赖它的"观察者"都会收到通知并自动更新。这种模式的优势在于解耦被观察者和观察者——双方无需知道对方的具体实现,只需通过统一接口交互,新增或删除观察者时无需修改被观察者代码。

结合家具生产场景,各角色对应关系如下:

  • 被观察者(主题):家具工厂,负责生产家具并维护观察者列表,状态变化(如新款家具下线、产能调整)时通知所有观察者。

  • 观察者:经销商、零售商、意向客户等,需要关注工厂状态变化,收到通知后执行对应操作(备货、上架、咨询)。

  • 核心约定:工厂提供"注册观察者""移除观察者""通知观察者"的统一接口;观察者提供"接收通知并处理"的统一接口。

二、观察者模式结构拆解(家具生产场景)

观察者模式通常包含4个核心组件,结合家具生产场景的具体实现如下:

  1. 抽象观察者(Abstract Observer):定义观察者的统一接口,包含一个"更新通知"方法。对应场景中的"家具关注者"接口,所有需要关注工厂动态的角色都要实现该接口。

  2. 具体观察者(Concrete Observer):实现抽象观察者接口,定义收到通知后的具体操作。对应场景中的经销商、零售商、意向客户。

  3. 抽象被观察者(Abstract Subject):定义被观察者的统一接口,包含"添加观察者""移除观察者""通知所有观察者"的方法,以及维护观察者列表和自身状态的属性。对应场景中的"家具生产主体"接口。

  4. 具体被观察者(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方法,所有注册的观察者都会收到更新,避免了人工逐一通知的繁琐。

  • 灵活控制:通过attachdetach方法,观察者可以自由关注或取消关注工厂,符合实际场景中"客户取消预约""经销商终止合作"等需求。

五、观察者模式的适用场景总结

结合本次家具生产的例子,当业务中存在以下场景时,优先考虑观察者模式:

  1. 一个对象状态变化需要联动多个对象更新,如工厂生产状态变化联动经销商、零售商、客户;

  2. 需要解耦被通知者和通知者,避免两者直接依赖,如工厂无需知道客户的具体信息,只需通过统一接口通知;

  3. 需要动态添加或删除被通知者,如新增家装公司关注工厂、客户取消关注。

在C++实际开发中,观察者模式还常用于GUI界面(如按钮点击联动多个组件更新)、日志系统(如日志级别变化联动多个输出端)等场景,是一种实用性极高的设计模式。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐