目录

引言

一、观察者模式的基本概念

核心思想

观察者模式的结构

UML图

应用场景

二、观察者模式的优点与缺点

优点

缺点

三、C++实现观察者模式

定义观察者接口

定义被观察者接口

实现具体观察者和被观察者

客户端代码

四、总结


引言

在软件开发中,设计模式是解决问题的最佳实践,它们帮助开发者以可重用、可维护和可扩展的方式设计系统。观察者模式(Observer Pattern)是其中一种非常流行的设计模式,它定义了一种一对多的依赖关系,使得当一个对象的状态发生变化时,所有依赖于它的对象都会得到通知并自动更新。本文将详细介绍观察者模式的概念、结构及其在C++中的实现。

一、观察者模式的基本概念

观察者模式,有时也被称为发布-订阅模式、模型-视图模式、源-收听者模式或从属者模式,是软件设计模式的一种。在这种模式中,一个目标对象(被观察者)管理所有依赖于它的观察者对象,并在其状态改变时主动通知这些观察者。这通常通过调用观察者提供的方法来实现。

核心思想

观察者模式是一种行为设计模式,其核心思想在于建立一种对象间的一对多依赖关系,使得当一个对象(被观察者)的状态发生改变时,所有依赖于它的对象(观察者)都会得到通知并自动更新。这种机制提供了一种灵活的、松耦合的方式来处理对象间的交互,使得系统更加易于维护和扩展。

观察者模式的结构

观察者模式主要包含以下几个角色:

  • Subject(被观察者)
    • 维护一个观察者列表。
    • 提供接口让观察者注册和注销自己。
    • 当状态发生变化时,通知所有注册的观察者。
  • Observer(观察者)
    • 提供一个更新接口,以便在接收到被观察者状态变化的通知时执行相应的操作。
    • 具体实现中,观察者通常会实现一个共同的接口或继承自一个抽象类。
  • ConcreteSubject(具体被观察者)
    • 实现了被观察者的接口,维护了具体状态及观察者列表。
    • 当状态变化时,遍历观察者列表并通知所有观察者。
  • ConcreteObserver(具体观察者)
    • 实现了观察者的接口,定义了接收到通知后需要执行的具体操作。

UML图

应用场景

观察者模式在多种应用场景中都能发挥重要作用,包括但不限于:

  • 图形用户界面(GUI):在GUI中,视图组件可以作为观察者,监听模型(被观察者)的状态变化,并更新显示。
  • 事件处理系统:在事件驱动的应用程序中,事件源(被观察者)在事件发生时通知所有注册的事件监听器(观察者)。
  • 业务对象交互:在业务逻辑中,当一个业务对象的状态变化需要通知其他业务对象时,可以使用观察者模式。

二、观察者模式的优点与缺点

优点

  1. 解耦:观察者和被观察者之间通过抽象层进行交互,降低了它们之间的耦合度,提高了系统的灵活性和可扩展性。
  2. 支持广播通信:被观察者可以同时通知多个观察者,简化了系统设计的复杂度。
  3. 满足开闭原则:增加新的观察者或被观察者时,无需修改现有代码,符合开闭原则。
  4. 提高复用性:观察者和被观察者都可以作为独立的模块进行复用。

缺点

  1. 性能问题:如果被观察者状态变化频繁或观察者数量众多,可能导致通知操作消耗大量时间和资源,影响系统性能。
  2. 循环依赖:观察者之间可能存在循环依赖,导致系统难以理解和维护。
  3. 通知顺序问题:在某些情况下,观察者的通知顺序可能很重要,但观察者模式本身并不保证通知的顺序。
  4. 缺乏状态变化细节:观察者模式只通知观察者状态发生了变化,但不提供状态变化的具体细节,可能需要观察者自行查询。

三、C++实现观察者模式

在C++中实现观察者模式,我们需要定义观察者接口、被观察者接口以及它们的具体实现。以下是一个简单的实现示例。

定义观察者接口

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

定义被观察者接口

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

实现具体观察者和被观察者

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

class ConcreteSubject : public Subject {
private:
    std::vector<std::shared_ptr<Observer>> observers;

public:
    void registerObserver(const std::shared_ptr<Observer>& observer) override {
        observers.push_back(observer);
    }

    void removeObserver(const std::shared_ptr<Observer>& observer) override {
        auto it = std::find(observers.begin(), observers.end(), observer);
        if (it != observers.end()) {
            observers.erase(it);
        }
    }

    void notifyObservers(const std::string& message) override {
        for (auto& observer : observers) {
            observer->update(message);
        }
    }
};

客户端代码

int main() {  
    std::shared_ptr<ConcreteSubject> subject = std::make_shared<ConcreteSubject>();  
    std::shared_ptr<Observer> observer1 = std::make_shared<ConcreteObserver>();  
    std::shared_ptr<Observer> observer2 = std::make_shared<ConcreteObserver>();  
  
    subject->registerObserver(observer1);  
    subject->registerObserver(observer2);  
  
    subject->notifyObservers("Hello, Observers!");  
  
    subject->removeObserver(observer1);  
    subject->notifyObservers("Hello again, Observers!");  
  
    return 0;  
}

四、总结

观察者模式是一种强大的设计模式,通过实现对象间的一对多依赖关系,使得当被观察者状态变化时,能够自动通知并更新所有观察者。它解耦了观察者和被观察者,提高了系统的灵活性和可扩展性。然而,该模式也存在一些缺点,如状态频繁变化或观察者众多时可能影响性能,以及可能存在的循环依赖问题。此外,观察者模式通常只通知状态变化,而不提供具体细节,可能需要观察者自行查询。尽管如此,观察者模式在事件处理、GUI设计、业务对象交互等多个领域都有广泛应用,是软件开发中不可或缺的设计模式之一。通过合理使用观察者模式,可以构建出更加灵活、易于维护和扩展的系统。

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐