【C++设计模式之Observer观察者模式】

Observer观察者模式


模式定义

观察者模式:定义对象间的一种一对多(变化)的依赖关系,以便当一个对象(Subject)的状态发生改变时,所有依赖于它的对象都得到通知并自动更新。

允许对象(观察者)订阅另一个对象(被观察者)的状态变化,并在状态变化时自动接收通知。

动机(Motivation)

  • 在软件构建过程中,我们需要为某些对象建立一种"通知依赖关系"------一个对象(目标对象)的状态发送改变,所有的依赖对象(观察者对象)都将得到通知。如果这样的依赖关系过于密切,将使软件不能很好地抵御变化。
  • 使用面向对象技术,可以将这种依赖关系弱化,并形成一种稳定的依赖关系。从而实现软件体系结构的松耦合。

结构(Structure)

应用场景一(气象站)实现步骤

1.定义观察者接口

observer.h头文件

cpp 复制代码
#pragma once
#include<vector>
#include<algorithm>

//观察者接口
class Observer {
public:
	virtual ~Observer() = default;
	virtual void update() = 0;     //更新方法(纯虚函数)
};

2.定义被观察者(主题)接口

subject.h头文件

cpp 复制代码
#pragma once
#include "observer.h"

class Subject {
public:
	virtual ~Subject() = default;
	virtual void attach(Observer*observer) = 0;   //注册观察者
	virtual void detach(Observer*observer) = 0;   //移除观察者
	virtual void notify() = 0;                    //通知观察者

protected:
	std::vector<Observer*> observers_;             //存储观察则列表
};

3.实现具体被观察者对象(气象站)

concretesubject.h

cpp 复制代码
#pragma once
#include"subject.h"

class WeatherStation :public Subject {
public:
	//注册观察者
	void attach(Observer* observer)override {
		observers_.push_back(observer);
	}

	//移除观察者
	void detach(Observer*observer)override {
		auto it = std::remove(observers_.begin(), observers_.end(), observer);
		observers_.erase(it, observers_.end());
	}

	//通知所有观察者
	void notify()override {
		for (auto observer : observers_) {
			observer->update();
		}
	}

	//更新气象数据并触发通知
	void setMeasurements(float temperature, float humidity) {
		temperature_ = temperature;
		humidity_ = humidity;
		notify();    //数据变化时通知观察者
	}

	//获取数据(供观察者拉取)
	float getTemperature()const { return temperature_; }
	float getHumidity()const { return humidity_; }

private:
	float temperature_ = 0.0f;
	float humidity_ = 0.0f;
};

4.实现具体观察者(例如:显示屏)

concreteobserver.h

cpp 复制代码
#pragma once
#include<iostream>
#include"observer.h"
#include"concretesubject.h"
class Display :public Observer {
public:
	explicit Display(WeatherStation&station):station_(station){}

	//当被观察者通知时,更新显示
	void update()override {
		std::cout << "Temperature: " << station_.getTemperature()
			<< " ℃,Humidity : " << station_.getHumidity() << "% \n";
	}
private:
	WeatherStation& station_;
};

5.main.cpp中使用示例

cpp 复制代码
#include <iostream>
#include"concretesubject.h"
#include"concreteobserver.h"

int main()
{
	WeatherStation station;  // 被观察者(气象站)
	Display display1(station);  // 观察者1(显示屏)
	Display display2(station);  // 观察者2

	// 注册观察者
	station.attach(&display1);
	station.attach(&display2);

	// 更新数据,自动触发观察者更新
	station.setMeasurements(25.5f, 60.0f);
	station.setMeasurements(26.0f, 55.0f);

	// 移除一个观察者
	station.detach(&display2);
	station.setMeasurements(27.0f, 50.0f);

	return 0;
}

6.输出结果

cpp 复制代码
Temperature: 25.5 ℃,Humidity : 60%
Temperature: 25.5 ℃,Humidity : 60%
Temperature: 26 ℃,Humidity : 55%
Temperature: 26 ℃,Humidity : 55%
Temperature: 27 ℃,Humidity : 50%

7. 关键点

  • 松耦合:观察者和被观察者通过接口交互,无需知道彼此的具体实现。

  • 推拉模型:

    • 推模式:被观察者将数据直接推送给观察者(通过 update 方法参数)。

    • 拉模式:观察者主动从被观察者拉取数据(本例中使用 getTemperature() 和 getHumidity())。

  • 内存管理:需确保观察者的生命周期覆盖被观察者,或使用 shared_ptr 管理资源。

应用场景二(温度传感器)实现步骤

1.定义观察者接口

observer.h

cpp 复制代码
#pragma once
//定义观察者接口
class Observer {
public:
	virtual ~Observer() = default;
	virtual void update() = 0;    //更新方法
};

2.定义被观察者接口

subject.h

cpp 复制代码
#pragma once
#include"observer.h"
#include<vector>
class Subject {
public:
	virtual ~Subject() = default;
	virtual void attach(Observer*observer) = 0;  //注册观察者
	virtual void detach(Observer*observer) = 0;  //移除观察者

	virtual void notify() = 0;                   //通知观察者
protected:
	std::vector<Observer*>observers_;
};

3.实现具体被观察者(温度传感器)

concretesubject.h

cpp 复制代码
#pragma once
#include"subject.h"
#include <algorithm>

class TemperatureSensor :public Subject {
public:
	void attach(Observer*observer)override {
		observers_.push_back(observer);
	}

	void detach(Observer* observer) override {
		auto it = std::remove(observers_.begin(), observers_.end(), observer);
		observers_.erase(it, observers_.end());
	}

	void notify() override {
		for (auto observer : observers_) {
			observer->update();
		}
	}

	void setTemperature(float temp) {
		temperature_ = temp;
		notify();  // 温度变化时通知所有观察者
	}

	float getTemperature() const { return temperature_; }

private:
	float temperature_ = 0.0f;
};

4.实现具体观察者(温度显示屏)

concreteobserver.h

cpp 复制代码
#pragma once
#include"observer.h"
#include "concretesubject.h"
#include<iostream>

class TemperatureDisplay :public Observer {
public:
	explicit TemperatureDisplay(TemperatureSensor&sensor):sensor_(sensor){}

	void update()override {
		std::cout << "当前温度: " << sensor_.getTemperature() << " ℃\n";
	}
private:
	TemperatureSensor& sensor_;
};

5.使用示例

cpp 复制代码
#include"concreteobserver.h"
#include"concretesubject.h"

int main() {
	TemperatureSensor sensor;
	TemperatureDisplay display(sensor);

	sensor.attach(&display);
	sensor.setTemperature(25.5f);  // 输出:当前温度: 25.5°C

	sensor.detach(&display);
	sensor.setTemperature(26.0f);  // 无输出

	return 0;
}

要点总结

  • 使用面向对象的抽象,Observer模式使得我们可以独立地改变目标与观察者,从而使二者之间的依赖关系达致松耦合。
  • 目标发送通知时,无需指定观察者,通知(可以携带通知信息作为参数)会自动传播。
  • 观察者自己决定是否需要订阅通知,目标对象对此一无所知。
  • Observer模式是基于事件的UI框架中非常常用的设计模式,也是MVC模式的一个重要组成部分。
相关推荐
音草24 分钟前
AVL 树详解:从概念到 C++ 实现
c++
凉茶钱34 分钟前
list:哨兵节点,const_iterator 和 const iterator的区别与迭代器失效
数据结构·c++·list
沫璃染墨43 分钟前
从零入门计算机网络系列(六):TCP套接字编程实战——从listen监听到客户端与服务器通信
linux·服务器·c++·tcp/ip·计算机网络·tcp
努力实干1 小时前
C++ 面向对象与工程架构
开发语言·c++·架构
代钦塔拉1 小时前
【C++/Qt 进阶】设计模式系列(6):桥接模式——把“两个独立变化的维度“拆开
c++·qt·设计模式
haluhalu.1 小时前
深入理解AIAgent(1.3)--- 设计模式
人工智能·python·设计模式·langchain
青少儿编程课堂2 小时前
蓝桥杯·全国青少年信息素养大赛·电子学会Python/C/C++考级:任意进制互转与大数多进制加法解析
c++·python·算法·bfs·信息学竞赛
Shadow(⊙o⊙)2 小时前
仿muduo实现高并发服务器——EPOLL设置与移除Poller.hpp管理Channel
运维·服务器·c++
闻缺陷则喜何志丹2 小时前
【C++特性及类库】多线程
开发语言·c++·多线程·语言特性·系统库
多弗朗皮卡丘2 小时前
C++ 哈希(下)
c++·算法·哈希算法