当前位置: 首页 > news >正文

【第16节】C++设计模式(行为模式)-Observer(观察者)模式

一、问题背景

        观察者模式(Observer Pattern)是应用最广泛的设计模式之一,尤其是在实现 **Model/View/Controller (MVC)** 架构时,观察者模式起到了核心作用。MVC 架构通过将业务逻辑(Model)、用户界面(View)和控制器(Controller)分离,实现了系统的高内聚和低耦合。

        在软件开发中,观察者模式的核心思想是:**当一个对象(Subject)的状态发生变化时,所有依赖于它的对象(Observers)都会自动收到通知并更新**。这种模式非常适合处理一对多的依赖关系,例如:

(1)数据统计与展示:同一组数据可以通过表格、柱状图、百分比等多种形式展示。当数据发生变化时,所有展示形式都需要同步更新。
(2)事件驱动系统:例如 GUI 框架中的按钮点击事件,多个组件可能需要响应同一个事件。

二、模式选择与实现

观察者模式的核心结构如下:

(1)Subject(目标):维护一个观察者列表,提供注册(Attach)和注销(Detach)操作,并在状态变化时通知所有观察者(Notify)。
(2)Observer(观察者):定义一个更新接口(Update),当 Subject 状态变化时,Observer 会收到通知并更新自身状态。

        观察者模式的关键特点是:Observer 的更新操作是延迟执行的,只有当 Subject 调用 Notify 时,所有 Observer 才会同步更新。

实现

以下是观察者模式的完整代码实现,使用 C++ 编写。

代码片段 1:Subject.h

// Subject.h
#ifndef _SUBJECT_H_
#define _SUBJECT_H_

#include <list>
#include <string>
using namespace std;

typedef string State; // 定义状态类型

class Observer; // 前置声明

// Subject 类:目标对象,维护观察者列表
class Subject {
public:
    virtual ~Subject();
    virtual void Attach(Observer* obv); // 注册观察者
    virtual void Detach(Observer* obv); // 注销观察者
    virtual void Notify();              // 通知观察者
    virtual void SetState(const State& st) = 0; // 设置状态
    virtual State GetState() = 0;               // 获取状态

protected:
    Subject();

private:
    list<Observer*>* _obvs; // 观察者列表
};

// ConcreteSubject 类:具体的目标对象
class ConcreteSubject : public Subject {
public:
    ConcreteSubject();
    ~ConcreteSubject();
    State GetState();
    void SetState(const State& st);

protected:
private:
    State _st; // 目标状态
};

#endif //~_SUBJECT_H_

代码片段 2:Subject.cpp

// Subject.cpp
#include "Subject.h"
#include "Observer.h"
#include <iostream>
using namespace std;

// Subject 构造函数
Subject::Subject() {
    _obvs = new list<Observer*>; // 初始化观察者列表
}

Subject::~Subject() {}

// 注册观察者
void Subject::Attach(Observer* obv) {
    _obvs->push_front(obv);
}

// 注销观察者
void Subject::Detach(Observer* obv) {
    if (obv != NULL)
        _obvs->remove(obv);
}

// 通知所有观察者
void Subject::Notify() {
    list<Observer*>::iterator it;
    for (it = _obvs->begin(); it != _obvs->end(); it++) {
        (*it)->Update(this); // 调用观察者的 Update 方法
    }
}

// ConcreteSubject 构造函数
ConcreteSubject::ConcreteSubject() {
    _st = '\0'; // 初始化状态
}

ConcreteSubject::~ConcreteSubject() {}

// 获取状态
State ConcreteSubject::GetState() {
    return _st;
}

// 设置状态
void ConcreteSubject::SetState(const State& st) {
    _st = st;
}

代码片段 3:Observer.h

// Observer.h
#ifndef _OBSERVER_H_
#define _OBSERVER_H_

#include "Subject.h"
#include <string>
using namespace std;

typedef string State;

// Observer 类:观察者基类
class Observer {
public:
    virtual ~Observer();
    virtual void Update(Subject* sub) = 0; // 更新接口
    virtual void PrintInfo() = 0;         // 打印信息

protected:
    Observer();
    State _st; // 观察者状态

private:
};

// ConcreteObserverA 类:具体观察者 A
class ConcreteObserverA : public Observer {
public:
    ConcreteObserverA(Subject* sub);
    virtual ~ConcreteObserverA();
    void Update(Subject* sub);
    void PrintInfo();

protected:
private:
    Subject* _sub; // 指向目标对象的指针
};

// ConcreteObserverB 类:具体观察者 B
class ConcreteObserverB : public Observer {
public:
    ConcreteObserverB(Subject* sub);
    virtual ~ConcreteObserverB();
    void Update(Subject* sub);
    void PrintInfo();

protected:
private:
    Subject* _sub; // 指向目标对象的指针
};

#endif //~_OBSERVER_H_

代码片段 4:Observer.cpp

// Observer.cpp
#include "Observer.h"
#include "Subject.h"
#include <iostream>
using namespace std;

Observer::Observer() {
    _st = '\0'; // 初始化状态
}

Observer::~Observer() {}

// ConcreteObserverA 构造函数
ConcreteObserverA::ConcreteObserverA(Subject* sub) {
    _sub = sub;
    _sub->Attach(this); // 注册到目标对象
}

ConcreteObserverA::~ConcreteObserverA() {
    _sub->Detach(this); // 从目标对象注销
    if (_sub != 0)
        delete _sub;
}

// 更新状态
void ConcreteObserverA::Update(Subject* sub) {
    _st = sub->GetState();
    PrintInfo();
}

// 打印信息
void ConcreteObserverA::PrintInfo() {
    cout << "ConcreteObserverA observer.... " << _sub->GetState() << endl;
}

// ConcreteObserverB 构造函数
ConcreteObserverB::ConcreteObserverB(Subject* sub) {
    _sub = sub;
    _sub->Attach(this); // 注册到目标对象
}

ConcreteObserverB::~ConcreteObserverB() {
    _sub->Detach(this); // 从目标对象注销
    if (_sub != 0)
        delete _sub;
}

// 更新状态
void ConcreteObserverB::Update(Subject* sub) {
    _st = sub->GetState();
    PrintInfo();
}

// 打印信息
void ConcreteObserverB::PrintInfo() {
    cout << "ConcreteObserverB observer.... " << _sub->GetState() << endl;
}

代码片段 5:main.cpp

// main.cpp
#include "Subject.h"
#include "Observer.h"
#include <iostream>
using namespace std;

int main(int argc, char* argv[]) {
    ConcreteSubject* sub = new ConcreteSubject(); // 创建目标对象
    Observer* o1 = new ConcreteObserverA(sub);    // 创建观察者 A
    Observer* o2 = new ConcreteObserverB(sub);    // 创建观察者 B

    sub->SetState("old"); // 设置初始状态
    sub->Notify();        // 通知观察者

    sub->SetState("new"); // 更新状态
    sub->Notify();        // 通知观察者

    return 0;
}

代码说明

(1)Subject 维护一个观察者列表(`list<Observer*>`),通过 `Attach` 和 `Detach` 方法管理观察者。
(2)Observer 定义了 `Update` 接口,当 Subject 状态变化时,Observer 会收到通知并更新自身状态。
(3)ConcreteSubject 是具体的 Subject 实现,负责维护状态并通知观察者。
(4)ConcreteObserverA 和 ConcreteObserverB 是具体的观察者实现,它们在 `Update` 方法中更新状态并打印信息。

        运行示例程序后,可以看到当 Subject 的状态从 `"old"` 变为 `"new"` 时,所有观察者都会同步更新并打印最新的状态。

三、总结讨论

观察者模式是软件开发中非常重要的模式之一,广泛应用于以下场景:

(1)MVC 架构:Model 是 Subject,View 是 Observer,当 Model 数据变化时,View 会自动更新。
(2)事件驱动系统:例如 GUI 框架中的事件处理机制。
(3)发布-订阅系统:Subject 是发布者,Observer 是订阅者,订阅者会收到发布者的通知。

        在 Java 中,观察者模式通过 `Observable` 类和 `Observer` 接口实现。其核心思想与 C++ 实现类似,但提供了更高级的封装和易用性。

 

        观察者模式通过解耦 Subject 和 Observer,实现了对象之间的松耦合。它非常适合处理一对多的依赖关系,尤其是在需要动态更新多个对象的场景中。尽管观察者模式在大型系统中非常有用,但也需要注意避免过度使用,以免导致系统复杂性增加。

相关文章:

  • MySQL增量更新数据:高效同步策略与PanguSync实战指南
  • 网络空间安全(14)编辑器漏洞
  • FastExcel简介以及源码解析
  • 达梦数据库关于参数PK_WITH_CLUSTER的改动分析
  • MySQL环境搭建
  • MCC(Matthews Correlation Coefficient)分数
  • 【mysql】1273错误,Unknown collation: ‘utf8mb4_0900_ai_ci‘...
  • docker 常用容器启动 docker-compose.yml 配置文件详解
  • 如何使用Briefing打造私有视频会议系统结合内网穿透异地远程连接
  • 将自定义vue组件加载在Mapbox或Maplibre的marker和popup上
  • Qt 实现绘图板(支持橡皮擦与 Ctrl+Z 撤销功能)[特殊字符]
  • Spring Boot中对接Twilio以实现发送验证码和验证短信码
  • CAD2025电脑置要求
  • 蓝桥试题:破损的楼梯 3367
  • OSI七层网络结构和TCP/IP四层结构
  • [Windows] 多系统键鼠共享工具 轻松跨系统控制多台电脑
  • 【JavaSE-4】程序逻辑控制
  • SpringMVC请求处理流程:DispatcherServlet工作原理
  • 4.RabbitMQ工作模型
  • Linux中的进程间通信的方式及其使用场景
  • 盐城专业做网站的公司哪家好/友情链接交换源码
  • 网站显示后台登陆链接/行者seo
  • 深圳平湖做网站/商品热搜词排行榜
  • 动态网站开发考试/杭州明开seo
  • 长沙seo推广外包/seo技术培训东莞
  • 移动端网站咋做/今日全国最新疫情通报