自学内容网 自学内容网

C++软件设计模式之观察者模式

观察者模式的动机意图

观察者模式(Observer Pattern)是一种行为型设计模式,它定义了对象之间的一种一对多的依赖关系,使得当一个对象的状态发生改变时,所有依赖于它的对象都能够自动收到通知并进行相应的更新。

动机意图:

  • 解耦:观察者模式的动机在于解耦对象之间的关系。具体来说,它让一个对象(被观察者或主题)不需要知道具体有哪些对象(观察者)依赖于它,从而降低了对象之间的耦合度。
  • 自动通知:当被观察者的状态发生变化时,所有观察者都会自动收到通知,并执行相应的操作。这种机制使得系统更加灵活,易于扩展和维护。

适用场合

观察者模式适用于以下场景:

  1. 当一个对象的状态变化需要通知其他对象,并且你不知道这些对象的具体数量和类型时。例如,图形用户界面(GUI)中的按钮点击事件,可以通知多个监听器。
  2. 当需要在不修改被观察者代码的情况下,动态添加或删除观察者时。这种情况下,观察者模式可以实现松耦合的设计。
  3. 当一个对象的状态变化会影响多个其他对象,并且这些对象需要根据状态变化自动更新时。例如,股票价格的变化会影响多个投资者的策略。

观察者模式的变体

观察者模式有几种常见的变体,具体取决于通知机制、更新方式以及观察者的管理方式。以下是几种常见的变体:

  1. 推模型(Push Model)

    • 特点:被观察者主动将状态变化的信息推送给所有观察者。
    • 优点:观察者不需要知道被观察者的内部结构,只需要处理推送过来的数据。
    • 缺点:被观察者需要知道观察者的接口,可能会导致观察者和被观察者之间的耦合。
  2. 拉模型(Pull Model)

    • 特点:被观察者仅通知观察者状态已发生变化,观察者需要主动去拉取被观察者的具体状态。
    • 优点:观察者可以只拉取自己感兴趣的部分状态,减少不必要的数据传输。
    • 缺点:观察者需要了解被观察者的内部结构。
  3. 事件机制(Event-based Model)

    • 特点:被观察者通过事件通知观察者,观察者可以订阅特定类型的事件。
    • 优点:可以处理更复杂的事件类型,支持多种事件的订阅和处理。
    • 缺点:实现复杂度较高。
  4. 观察者队列(Observer Queue)

    • 特点:使用队列来管理观察者,当被观察者状态变化时,将通知放入队列中,观察者从队列中取出通知进行处理。
    • 优点:可以实现异步通知,提高系统的并发性能。
    • 缺点:可能引入额外的复杂性和延迟。
  5. 弱引用观察者(Weak Reference Observer)

    • 特点:使用弱引用(Weak Reference)来管理观察者,防止观察者对象未被释放时导致的内存泄漏。
    • 优点:可以避免内存泄漏问题。
    • 缺点:需要额外的机制来管理弱引用。

总结

观察者模式通过解耦对象之间的关系,提供了一种灵活且易于扩展的通知机制。它的变体如推模型、拉模型、事件机制等,使得它在不同的场景中可以有不同的实现方式。基于观察者模式的特点,发布-订阅模式、事件驱动架构、MVC模式等软件架构模式在现代软件开发中得到了广泛的应用。这些架构模式不仅提高了系统的灵活性和可维护性,还使得系统在面对变化时能够更加从容应对。

下面是观察者模式的不同变体的C++代码示例,包括推模型、拉模型、事件机制、观察者队列和弱引用观察者。

1. 推模型(Push Model)

在推模型中,被观察者将状态变化的信息主动推送给所有观察者。

示例代码
#include <iostream>
#include <vector>
#include <string>

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

// 具体观察者
class ConcreteObserver : public Observer {
public:
    void update(const std::string& message) override {
        std::cout << "Observer received message: " << message << std::endl;
    }
};

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

// 具体被观察者
class ConcreteSubject : public Subject {
private:
    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 (Observer* observer : observers) {
            observer->update(message);
        }
    }

    void changeState(const std::string& message) {
        std::cout << "Subject state changed. Notifying observers..." << std::endl;
        notify(message);
    }
};

int main() {
    ConcreteSubject subject;
    ConcreteObserver observer1;
    ConcreteObserver observer2;

    subject.attach(&observer1);
    subject.attach(&observer2);

    subject.changeState("Hello Observers!");

    subject.detach(&observer1);

    subject.changeState("Hello again!");

    return 0;
}

2. 拉模型(Pull Model)

在拉模型中,被观察者仅通知观察者状态已发生变化,观察者需要主动去拉取被观察者的具体状态。

示例代码
#include <iostream>
#include <vector>
#include <string>

// 被观察者接口
class Subject {
public:
    virtual std::string getState() const = 0;
    virtual void notify() = 0;
    virtual void setState(const std::string& state) = 0;
    virtual void attach(class Observer* observer) = 0;
    virtual void detach(class Observer* observer) = 0;
    virtual ~Subject() = default;
};

// 具体被观察者
class ConcreteSubject : public Subject {
private:
    std::string state;
    std::vector<class Observer*> observers;

public:
    std::string getState() const override {
        return state;
    }

    void setState(const std::string& state) override {
        this->state = state;
        notify();
    }

    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() override {
        for (Observer* observer : observers) {
            observer->update();
        }
    }
};

// 观察者接口
class Observer {
protected:
    Subject* subject;

public:
    Observer(Subject* subject) : subject(subject) {}
    virtual void update() = 0;
    virtual ~Observer() = default;
};

// 具体观察者
class ConcreteObserver : public Observer {
public:
    ConcreteObserver(Subject* subject) : Observer(subject) {}

    void update() override {
        std::string state = subject->getState();
        std::cout << "Observer received state: " << state << std::endl;
    }
};

int main() {
    ConcreteSubject subject;
    ConcreteObserver observer1(&subject);
    ConcreteObserver observer2(&subject);

    subject.attach(&observer1);
    subject.attach(&observer2);

    subject.setState("State 1");

    subject.detach(&observer1);

    subject.setState("State 2");

    return 0;
}

3. 事件机制(Event-based Model)

在事件机制中,被观察者通过事件通知观察者,观察者可以订阅特定类型的事件。

示例代码
#include <iostream>
#include <vector>
#include <string>
#include <map>
#include <functional>

// 事件类型
enum class EventType {
    StateChanged,
    DataUpdated
};

// 事件
class Event {
public:
    EventType type;
    std::string data;

    Event(EventType type, const std::string& data) : type(type), data(data) {}
};

// 观察者接口
class Observer {
public:
    virtual void handleEvent(const Event& event) = 0;
    virtual ~Observer() = default;
};

// 具体观察者
class ConcreteObserver : public Observer {
public:
    void handleEvent(const Event& event) override {
        std::cout << "Observer received event of type: " << static_cast<int>(event.type)
                  << " with data: " << event.data << std::endl;
    }
};

// 被观察者接口
class Subject {
private:
    std::map<EventType, std::vector<Observer*>> eventObservers;

public:
    void attach(EventType type, Observer* observer) {
        eventObservers[type].push_back(observer);
    }

    void detach(EventType type, Observer* observer) {
        auto& observers = eventObservers[type];
        observers.erase(std::remove(observers.begin(), observers.end(), observer), observers.end());
    }

    void notify(const Event& event) {
        auto& observers = eventObservers[event.type];
        for (Observer* observer : observers) {
            observer->handleEvent(event);
        }
    }

    void changeState(const std::string& state) {
        std::cout << "Subject state changed." << std::endl;
        notify(Event(EventType::StateChanged, state));
    }

    void updateData(const std::string& data) {
        std::cout << "Subject data updated." << std::endl;
        notify(Event(EventType::DataUpdated, data));
    }
};

int main() {
    Subject subject;
    ConcreteObserver observer1;
    ConcreteObserver observer2;

    subject.attach(EventType::StateChanged, &observer1);
    subject.attach(EventType::DataUpdated, &observer2);

    subject.changeState("New State");
    subject.updateData("New Data");

    subject.detach(EventType::StateChanged, &observer1);

    subject.changeState("Another State");

    return 0;
}

4. 观察者队列(Observer Queue)

在观察者队列中,使用队列来管理观察者,当被观察者状态变化时,将通知放入队列中,观察者从队列中取出通知进行处理。

示例代码
#include <iostream>
#include <queue>
#include <string>
#include <mutex>
#include <thread>
#include <condition_variable>

// 通知类型
class Notification {
public:
    virtual void process() = 0;
    virtual ~Notification() = default;
};

// 具体通知
class ConcreteNotification : public Notification {
private:
    std::string message;

public:
    ConcreteNotification(const std::string& message) : message(message) {}

    void process() override {
        std::cout << "Processing notification: " << message << std::endl;
    }
};

// 观察者队列
class ObserverQueue {
private:
    std::queue<Notification*> queue;
    std::mutex mutex;
    std::condition_variable cv;

public:
    void enqueue(Notification* notification) {
        std::lock_guard<std::mutex> lock(mutex);
        queue.push(notification);
        cv.notify_one();
    }

    void processQueue() {
        while (true) {
            std::unique_lock<std::mutex> lock(mutex);
            cv.wait(lock, [this] { return !queue.empty(); });
            Notification* notification = queue.front();
            queue.pop();
            lock.unlock();

            notification->process();
            delete notification;
        }
    }
};

int main() {
    ObserverQueue queue;

    std::thread worker([&queue]() { queue.processQueue(); });

    queue.enqueue(new ConcreteNotification("Notification 1"));
    queue.enqueue(new ConcreteNotification("Notification 2"));
    queue.enqueue(new ConcreteNotification("Notification 3"));

    worker.join();

    return 0;
}

5. 弱引用观察者(Weak Reference Observer)

在弱引用观察者中,使用弱引用(Weak Reference)来管理观察者,防止观察者对象未被释放时导致的内存泄漏。

示例代码
#include <iostream>
#include <vector>
#include <memory>
#include <string>
#include <functional>

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

// 具体观察者
class ConcreteObserver : public Observer {
public:
    void update(const std::string& message) override {
        std::cout << "Observer received message: " << message << std::endl;
    }
};

// 被观察者接口
class Subject {
public:
    virtual void attach(std::weak_ptr<Observer> observer) = 0;
    virtual void notify(const std::string& message) = 0;
    virtual ~Subject() = default;
};

// 具体被观察者
class ConcreteSubject : public Subject {
private:
    std::vector<std::weak_ptr<Observer>> observers;

public:
    void attach(std::weak_ptr<Observer> observer) override {
        observers.push_back(observer);
    }

    void notify(const std::string& message) override {
        observers.erase(std::remove_if(observers.begin(), observers.end(),
                                      [](const std::weak_ptr<Observer>& observer) {
                                          return observer.expired();
                                      }), observers.end());

        for (auto& observer : observers) {
            if (auto sharedObserver = observer.lock()) {
                sharedObserver->update(message);
            }
        }
    }

    void changeState(const std::string& message) {
        std::cout << "Subject state changed. Notifying observers..." << std::endl;
        notify(message);
    }
};

int main() {
    ConcreteSubject subject;

    auto observer1 = std::make_shared<ConcreteObserver>();
    auto observer2 = std::make_shared<ConcreteObserver>();

    subject.attach(observer1);
    subject.attach(observer2);

    subject.changeState("Hello Observers!");

    observer1.reset(); // 释放 observer1

    subject.changeState("Hello again!");

    return 0;
}

总结

以上是观察者模式的几种不同变体的C++代码示例。每种变体都有其适用的场景和优缺点,开发者可以根据具体的需求选择合适的实现方式。观察者模式的核心思想是解耦对象之间的关系,并通过通知机制实现对象之间的通信。

基于观察者模式特点的软件架构模式

观察者模式的特性使得它在许多软件架构中都有重要的应用,以下是几种基于观察者模式特点的软件架构模式:

  1. 发布-订阅模式(Publish-Subscribe Pattern)

    • 特点:发布-订阅模式是观察者模式的一种扩展,它将消息的发送者(发布者)和接收者(订阅者)完全解耦。发布者不需要知道订阅者的存在,订阅者也不需要知道发布者的存在。
    • 应用:常见的应用场景包括消息队列系统(如 Kafka、RabbitMQ)、事件驱动系统等。
    • 优点:系统组件之间的耦合度极低,适合构建分布式系统。
  2. 事件驱动架构(Event-Driven Architecture)

    • 特点:事件驱动架构是一种基于事件的架构模式,系统中的组件通过事件进行通信。事件的产生和处理通常基于观察者模式。
    • 应用:常见的应用场景包括图形用户界面、分布式系统、微服务架构等。
    • 优点:系统组件可以异步处理事件,提高系统的可扩展性和响应性。
  3. 模型-视图-控制器(MVC)模式

    • 特点:MVC模式将应用程序分为三个部分:模型(Model)、视图(View)和控制器(Controller)。模型是观察者模式中的被观察者,视图是观察者。当模型的状态发生变化时,视图会自动更新。
    • 应用:常见的应用场景包括Web应用程序、桌面应用程序等。
    • 优点:模型和视图之间的解耦,使得系统更易于维护和扩展。
  4. 观察者-被观察者链(Observer-Observable Chain)

    • 特点:在这种架构中,观察者和被观察者可以形成一个链式结构,每个被观察者可以同时是观察者。
    • 应用:常见的应用场景包括事件传播链、责任链模式等。
    • 优点:可以实现复杂的事件传播和处理机制。

原文地址:https://blog.csdn.net/joshua0137/article/details/144810980

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!