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

news/2025/3/6 23:13:30/

一、问题背景

        观察者模式(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);    // 创建观察者 AObserver* o2 = new ConcreteObserverB(sub);    // 创建观察者 Bsub->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,实现了对象之间的松耦合。它非常适合处理一对多的依赖关系,尤其是在需要动态更新多个对象的场景中。尽管观察者模式在大型系统中非常有用,但也需要注意避免过度使用,以免导致系统复杂性增加。


http://www.ppmy.cn/news/1577201.html

相关文章

VBA信息获取与处理第五节:如何在单个工作表中查找某个给定值

《VBA信息获取与处理》教程(版权10178984)是我推出第六套教程&#xff0c;目前已经是第一版修订了。这套教程定位于最高级&#xff0c;是学完初级&#xff0c;中级后的教程。这部教程给大家讲解的内容有&#xff1a;跨应用程序信息获得、随机信息的利用、电子邮件的发送、VBA互…

第三节:基于Winform框架的串口助手小项目---串口操作《C#编程》

知识是无尽的宝藏&#xff0c;学习的过程虽有挑战&#xff0c;但每一次突破都是对自我的升华&#xff0c;向着更优秀的自己全力进发。 -----------WHAPPY 本节将重点介绍&#xff0c;如何修改控件的属性、SerialPort类的使用及实现串口初始化的操作 1.修改控件属性 修改属性…

200W数据去重入库的几种方法及优缺点

一种是先将所有数据入库&#xff0c;再用SQL去重&#xff0c;导出再导入&#xff1b;另一种是之前讨论过的先内存去重再入库。 先明确两种方法的步骤&#xff1a; 方法一&#xff1a;全量入库 → SQL去重 → 导出 → 再导入 方法二&#xff1a;先内存去重 → 直接入库 接下…

2025年上海安卓发展机遇

文章目录 一、上海重点打造的产业集群规划二、安卓开发者的机遇与行动建议三、政策与资源支持总结 本文首发地址 https://h89.cn/archives/320.html 最新更新地址 https://gitee.com/chenjim/chenjimblog 一、上海重点打造的产业集群规划 根据上海市政府发布的《加快推进新型工…

PHP动态网站建设

如何配置虚拟主机 1. 学习提纲 本地发布与互联网发布&#xff1a;介绍了如何通过本地IP地址和互联网域名发布网站。 虚拟主机配置与访问&#xff1a;讲解了如何配置虚拟主机&#xff0c;并通过自定义域名访问不同的站点目录。 Web服务器配置&#xff1a;详细说明了如何配置A…

统一数据返回格式

目录 1、为什么需要统一数据返回格式2、统一数据返回格式的实现 1、为什么需要统一数据返回格式 统一数据返回格式的优点有很多&#xff0c;比如以下几个&#xff1a; 方便前端程序员更好的接收和解析后端数据接口返回的数据。降低前端程序员和后端程序员的沟通成本&#xff…

Mysql命令大全(创建数据库显示数据库删除数据库)

创建数据库 注意&#xff1a;创建数据库之前要先连接Mysql服务器 命令&#xff1a;create database <数据库名> 例1&#xff1a;建立一个名为xhkdb的数据库 mysql> create database xhkdb; 例2&#xff1a;创建数据库并分配用户 ①CREATE DATABASE 数据库名; …

C++程序设计语言标准库:STL概述

一、前言 本专题是作者为了加强C与数据结构的学习而作的记录&#xff0c;我所使用的STL版本为SGI STL&#xff0c;这里引用侯杰的《STL源码刨析》中的序言&#xff1a; STL&#xff0c;虽然是一套程序库&#xff08;library&#xff09;&#xff0c;却不只是一般印象中的程序库…