C++怎么发布订阅和观察者模式

发布时间:2022-04-14 16:57:38 作者:iii
来源:亿速云 阅读:419
# C++怎么实现发布订阅和观察者模式

## 1. 模式概述

### 1.1 观察者模式
观察者模式(Observer Pattern)定义了对象间的一对多依赖关系,当一个对象状态改变时,所有依赖它的对象都会自动收到通知。

### 1.2 发布订阅模式
发布订阅模式(Pub-Sub Pattern)是观察者模式的变体,通过引入消息代理(Broker)解耦发布者和订阅者,双方不直接通信。

### 1.3 核心区别
| 特性          | 观察者模式          | 发布订阅模式        |
|---------------|-------------------|-------------------|
| 耦合度        | 松耦合             | 完全解耦          |
| 通信方式      | 直接通知           | 通过消息代理      |
| 实时性        | 高                 | 可能延迟          |
| 实现复杂度    | 简单               | 较复杂            |

## 2. 观察者模式实现

### 2.1 经典实现

```cpp
#include <iostream>
#include <vector>
#include <algorithm>

// 观察者接口
class Observer {
public:
    virtual ~Observer() = default;
    virtual void update(const std::string& message) = 0;
};

// 主题接口
class Subject {
public:
    virtual ~Subject() = default;
    virtual void attach(Observer* observer) = 0;
    virtual void detach(Observer* observer) = 0;
    virtual void notify(const std::string& message) = 0;
};

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

// 具体观察者
class ConcreteObserver : public Observer {
    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;
    }
};

// 使用示例
int main() {
    ConcreteSubject subject;
    ConcreteObserver observer1("Observer1");
    ConcreteObserver observer2("Observer2");
    
    subject.attach(&observer1);
    subject.attach(&observer2);
    
    subject.notify("First Notification");
    
    subject.detach(&observer1);
    subject.notify("Second Notification");
    
    return 0;
}

2.2 现代C++改进版

#include <memory>
#include <vector>
#include <functional>

class Subject {
    std::vector<std::function<void(const std::string&)>> callbacks_;
    
public:
    void attach(std::function<void(const std::string&)> callback) {
        callbacks_.push_back(callback);
    }
    
    void notify(const std::string& message) {
        for (const auto& cb : callbacks_) {
            cb(message);
        }
    }
};

// 使用lambda表达式注册观察者
int main() {
    Subject subject;
    
    auto observer1 = [](const std::string& msg) {
        std::cout << "Observer1: " << msg << std::endl;
    };
    
    subject.attach(observer1);
    subject.attach([](const std::string& msg) {
        std::cout << "Observer2: " << msg << std::endl;
    });
    
    subject.notify("Event occurred!");
    
    return 0;
}

3. 发布订阅模式实现

3.1 基础实现

#include <map>
#include <vector>
#include <string>
#include <functional>

class PubSub {
    std::map<std::string, std::vector<std::function<void(const std::string&)>>> topics_;
    
public:
    void subscribe(const std::string& topic, 
                  std::function<void(const std::string&)> callback) {
        topics_[topic].push_back(callback);
    }
    
    void publish(const std::string& topic, const std::string& message) {
        if (topics_.find(topic) != topics_.end()) {
            for (const auto& callback : topics_[topic]) {
                callback(message);
            }
        }
    }
};

int main() {
    PubSub pubsub;
    
    // 订阅主题
    pubsub.subscribe("news", [](const std::string& msg) {
        std::cout << "Subscriber1 received news: " << msg << std::endl;
    });
    
    pubsub.subscribe("sports", [](const std::string& msg) {
        std::cout << "Subscriber2 received sports: " << msg << std::endl;
    });
    
    // 发布消息
    pubsub.publish("news", "New C++20 features released!");
    pubsub.publish("sports", "Team won the championship");
    
    return 0;
}

3.2 线程安全版本

#include <mutex>
#include <shared_mutex>

class ThreadSafePubSub {
    std::map<std::string, std::vector<std::function<void(const std::string&)>>> topics_;
    mutable std::shared_mutex mutex_;
    
public:
    void subscribe(const std::string& topic, 
                  std::function<void(const std::string&)> callback) {
        std::unique_lock lock(mutex_);
        topics_[topic].push_back(callback);
    }
    
    void publish(const std::string& topic, const std::string& message) {
        std::shared_lock lock(mutex_);
        auto it = topics_.find(topic);
        if (it != topics_.end()) {
            // 复制回调列表以避免锁持有期间执行用户代码
            auto callbacks = it->second;
            lock.unlock();
            
            for (const auto& callback : callbacks) {
                callback(message);
            }
        }
    }
};

4. 实际应用场景

4.1 观察者模式适用场景

4.2 发布订阅模式适用场景

5. 性能优化建议

  1. 回调存储优化

    • 使用std::vector存储回调函数
    • 预分配内存减少动态分配开销
  2. 线程模型选择

    • 单线程:简单无锁实现
    • 多线程:考虑读写锁(std::shared_mutex
  3. 内存管理

    • 使用std::shared_ptr管理观察者生命周期
    • 实现观察者自动注销机制
  4. 避免回调阻塞

    • 使用任务队列异步处理通知
    • 设置超时机制

6. 与其他模式的结合

6.1 与工厂模式结合

创建可配置的事件发布/订阅系统

class EventSystemFactory {
public:
    static std::unique_ptr<PubSub> createSimple() {
        return std::make_unique<PubSub>();
    }
    
    static std::unique_ptr<PubSub> createThreadSafe() {
        return std::make_unique<ThreadSafePubSub>();
    }
};

6.2 与装饰器模式结合

实现带日志记录功能的发布订阅系统

class LoggingPubSubDecorator : public PubSub {
    PubSub& wrapped_;
    
public:
    explicit LoggingPubSubDecorator(PubSub& wrapped) : wrapped_(wrapped) {}
    
    void publish(const std::string& topic, const std::string& message) override {
        std::cout << "Publishing to " << topic << ": " << message << std::endl;
        wrapped_.publish(topic, message);
    }
};

7. 常见问题与解决方案

7.1 循环引用问题

7.2 通知顺序问题

7.3 性能瓶颈

8. 总结

本文详细介绍了在C++中实现观察者模式和发布订阅模式的方法。观察者模式适合紧密耦合的场景,而发布订阅模式更适合分布式系统。现代C++特性(如lambda、智能指针等)可以大幅简化实现代码。在实际应用中,应根据具体需求选择合适的模式,并注意线程安全和性能优化问题。

两种模式的本质都是实现事件驱动架构,是构建响应式系统的重要工具。掌握这些模式可以帮助开发者设计出更灵活、更易维护的系统架构。 “`

推荐阅读:
  1. Redis 发布订阅模型
  2. redis发布订阅功能介绍

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

c++

上一篇:C++怎么进行类型转换

下一篇:C++11中的std::function怎么用

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》