观察者模式的核心结构

观察者模式由两个主要角色组成:Subject(主题)和Observer(观察者)。Subject维护一个观察者列表,提供注册和注销观察者的接口,并在状态变化时通知所有观察者。Observer定义一个更新接口,用于接收Subject的通知。

在C++中,可以使用抽象基类或接口定义Observer的通用行为:

class Observer {
public:
    virtual ~Observer() = default;
    virtual void update(const std::string& message) = 0;
};

Subject类通常包含管理观察者的方法:

class Subject {
private:
    std::vector<Observer*> observers_;
    
public:
    void attach(Observer* observer) {
        observers_.push_back(observer);
    }
    
    void detach(Observer* observer) {
        observers_.erase(std::remove(observers_.begin(), observers_.end(), observer), observers_.end());
    }
    
    void notify(const std::string& message) {
        for (auto observer : observers_) {
            observer->update(message);
        }
    }
};

具体实现示例

通过继承Observer接口创建具体观察者类,每个观察者实现自己的update方法以定义对通知的响应方式:

class ConcreteObserver : public Observer {
private:
    std::string name_;
    
public:
    explicit ConcreteObserver(const std::string& name) : name_(name) {}
    
    void update(const std::string& message) override {
        std::cout << name_ << " received: " << message << std::endl;
    }
};

Subject的具体实现可以扩展基本功能:

class ConcreteSubject : public Subject {
private:
    std::string state_;
    
public:
    void setState(const std::string& state) {
        state_ = state;
        notify(state);
    }
};

线程安全改进

标准实现存在线程安全问题。通过使用互斥锁保护观察者列表:

#include <mutex>

class ThreadSafeSubject : public Subject {
private:
    std::mutex mtx_;
    
public:
    void attach(Observer* observer) override {
        std::lock_guard<std::mutex> lock(mtx_);
        Subject::attach(observer);
    }
    
    void detach(Observer* observer) override {
        std::lock_guard<std::mutex> lock(mtx_);
        Subject::detach(observer);
    }
    
    void notify(const std::string& message) override {
        std::lock_guard<std::mutex> lock(mtx_);
        Subject::notify(message);
    }
};

性能优化策略

为避免在通知期间持有锁时间过长,可以复制观察者列表:

void notify(const std::string& message) override {
    std::vector<Observer*> observers_copy;
    {
        std::lock_guard<std::mutex> lock(mtx_);
        observers_copy = observers_;
    }
    
    for (auto observer : observers_copy) {
        observer->update(message);
    }
}

对于高频事件,可采用事件队列机制,将通知放入队列由单独线程处理。

智能指针管理

使用shared_ptr和weak_ptr避免内存管理问题:

class Observer : public std::enable_shared_from_this<Observer> {
public:
    virtual ~Observer() = default;
    virtual void update(const std::string& message) = 0;
};

class Subject {
private:
    std::vector<std::weak_ptr<Observer>> observers_;
    
public:
    void attach(std::shared_ptr<Observer> observer) {
        observers_.push_back(observer);
    }
    
    void notify(const std::string& message) {
        for (auto it = observers_.begin(); it != observers_.end(); ) {
            if (auto observer = it->lock()) {
                observer->update(message);
                ++it;
            } else {
                it = observers_.erase(it);
            }
        }
    }
};

模板化实现

使用模板实现类型安全的观察者模式:

template<typename T>
class Observer {
public:
    virtual ~Observer() = default;
    virtual void update(const T& data) = 0;
};

template<typename T>
class Subject {
private:
    std::vector<Observer<T>*> observers_;
    
public:
    void attach(Observer<T>* observer) {
        observers_.push_back(observer);
    }
    
    void notify(const T& data) {
        for (auto observer : observers_) {
            observer->update(data);
        }
    }
};

实际应用场景

在GUI开发中,按钮控件可作为Subject,各种UI元素作为Observer响应点击事件。游戏开发中,成就系统可以观察玩家状态变化。分布式系统中,服务可用性监控也常采用此模式。

// GUI按钮示例
class Button : public Subject {
public:
    void click() {
        notify("button clicked");
    }
};

class Label : public Observer {
public:
    void update(const std::string& message) override {
        if (message == "button clicked") {
            setText("Button was clicked");
        }
    }
    
    void setText(const std::string& text) {
        // 更新标签文本
    }
};

与其他模式结合

观察者模式常与中介者模式结合使用,通过中介者管理复杂的观察关系。在MVC架构中,模型作为Subject,视图作为Observer,实现数据与显示的分离。

// 结合中介者模式
class Mediator {
private:
    std::unordered_map<std::string, std::vector<Observer*>> subscriptions_;
    
public:
    void subscribe(const std::string& event, Observer* observer) {
        subscriptions_[event].push_back(observer);
    }
    
    void publish(const std::string& event, const std::string& message) {
        for (auto observer : subscriptions_[event]) {
            observer->update(message);
        }
    }
};
Logo

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

更多推荐