C++ 14观察者模式

本文介绍了C++ 14中的观察者模式,也称为发布-订阅模式。该模式定义了一对多的依赖关系,允许多个观察者对象监听某主题对象。当主题状态改变时,会通知所有观察者进行自动更新。内容包括Subject、Observer、ConcreteSubject和ConcreteObserver类的解释,并通过公司场景举例,描述了老板来上班时秘书如何通知员工的案例,附带了相关代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

观察者模式又叫发布-订阅(Publish/Subscribe)模式。

 

观察者模式的定义:

观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主体对象在状态发生改变时,会通知所有观察者对象,使它们能够自动更新自己。

观察者模式结构图如下:


Subject,它把所有对观察者对象的引用保存在一个列表(list或vector)里,每个主题都可以有任何数量的观察者,抽象主题提供两个接口,通过Attach/Detach函数添加/移除观察者对象,通过Notify函数通知每一个注册过的观察者对象。

Observer,是一个抽象观察者,为所有的具体观察者定义一个接口,在得到主题的通知时更新自己。

ConcreteSubject类,具体主题类,将有关状态存入具体观察者对象;在具体主题的内部状态改变时,给所有登记过的观察者发出通知。

ConcreteObserver,具体观察者类,实现抽象观察者角色所要求的更新接口,以便使本身的状态和主题的状态相协调。

列举一个案例:

假如在公司时,当老板没来之前,员工想干其他的事情(看股票行情,看NBA球赛),当老板来上班时,前台秘书可以通知那些干其他事的员工,说老板来了,假装认真工作,这样秘书就可以通知所有已被告知要通知的员工。

结构图如下:


具体代码如下:

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

class Subject;//使用Subject类
//抽象观察者
class Observer
{
protected:
	string name;
	Subject* sub;
public:
	Observer(string name, Subject* sub) :name(name), sub(sub)
	{ }
	virtual void Update()=0; //定义一个纯虚函数
};
//看股票的同事
class StockObserver :public Observer //继承
{
public:
	StockObserver(string na, Subject* sub) :Observer(na, sub)
	{ }
	void Update();
};
//看NBA的同事们
class NBAObserver :public Observer//继承
{
public:
	NBAObserver(string na, Subject* sub) :Observer(na, sub)
	{ }
	void Update();
};

//抽象主题类
class Subject
{
protected:
	list<Observer*> observers;
public:
	string action;
	virtual void Attach(Observer* obs) = 0;
	virtual void Detach(Observer* obs) = 0;
	virtual void Notify()=0;

};
//具体主题类,秘书
class Secretary :public Subject//继承s
{
	void Attach(Observer *obs)
	{
		observers.push_back(obs);
	}
	void Detach(Observer *obs)
	{
		list<Observer*>::iterator iter = observers.begin();
		while(iter != observers.end())
		{
			if ((*iter) == obs)
			{
				observers.erase(iter);
			}
			++iter;
		}
	}

	void Notify()//通知函数
	{
		list<Observer*>::iterator iter = observers.begin();
		while (iter != observers.end())
		{
			(*iter)->Update();
			++iter;
		}
	}
};

void StockObserver::Update()
{
	cout << name << " 收到消息:" << sub->action << endl;
	if (sub->action == "经理来了")
	{
		cout << "我马上关闭股票,装作很认真工作的样子" << endl;
	}
}

void NBAObserver::Update()
{
	cout << name << " 收到消息:" << sub->action << endl;
	if (sub->action == "经理来了")
	{
		cout << "我马上关闭NBA,装作很认真工作的样子" << endl;
	}
}

int main()
{
	Subject *secretotry = new Secretary();//消息监视

	Observer *obs1 = new StockObserver("小王", secretotry);//订阅消息
	Observer *obs2 = new NBAObserver("小刘", secretotry);
	Observer *obs3 = new StockObserver("小张", secretotry);

	secretotry->Attach(obs1);//增加队列
	secretotry->Attach(obs2);
	secretotry->Attach(obs3);

	secretotry->action = "经理来了";
	secretotry->Notify();

	return 0;
}


### C++14 中实现观察者模式的示例代码及解析 #### 示例代码 以下是基于引用的内容和标准设计模式理论,在 C++14 下实现的一个简单的观察者模式示例: ```cpp #include <iostream> #include <vector> #include <memory> // 定义 Observer 接口 class Observer { public: virtual ~Observer() = default; virtual void update(const std::string& message) = 0; // 更新方法 }; // 定义 Subject 接口 class Subject { private: std::vector<std::shared_ptr<Observer>> observers_; // 存储观察者的容器 protected: void notifyObservers(const std::string& message) const { // 通知所有观察者 for (const auto& observer : observers_) { if (observer) { observer->update(message); } } } public: void registerObserver(std::shared_ptr<Observer> observer) { // 注册观察者 observers_.push_back(observer); } void removeObserver(std::shared_ptr<Observer> observer) { // 移除观察者 observers_.erase(std::remove(observers_.begin(), observers_.end(), observer), observers_.end()); } }; // 具体的主题类 class ConcreteSubject : public Subject { private: std::string state_; public: void setState(const std::string& newState) { // 设置状态并通知观察者 state_ = newState; notifyObservers(state_); } const std::string& getState() const { return state_; } // 获取当前状态 }; // 具体的观察者类 class ConcreteObserver : public Observer { private: std::weak_ptr<ConcreteSubject> subject_; // 使用弱指针避免循环引用 std::string name_; public: explicit ConcreteObserver(const std::string& name, std::shared_ptr<ConcreteSubject> subject) : name_(name), subject_(subject) {} void update(const std::string& message) override { // 当主题更新时调用此方法 std::cout << "Observer " << name_ << ": Received message - " << message << "\n"; } void subscribeToSubject() { // 订阅到某个主体 if (auto lockedSubject = subject_.lock()) { lockedSubject->registerObserver(shared_from_this()); } } void unsubscribeFromSubject() { // 取消订阅 if (auto lockedSubject = subject_.lock()) { lockedSubject->removeObserver(shared_from_this()); } } }; ``` --- #### 解析 1. **`Observer` 接口** `Observer` 是一个抽象基类,定义了一个虚函数 `update()`,所有的具体观察者都需要继承它并重写该方法。当被观察对象的状态发生变化时,会通过这个方法来通知观察者。 2. **`Subject` 接口** `Subject` 同样是一个抽象基类,提供了三个核心功能:注册 (`registerObserver`)、移除 (`removeObserver`) 和通知 (`notifyObservers`) 观察者的能力。这些操作由具体的子类负责实现。 3. **`ConcreteSubject` 类** 这是 `Subject` 的具体实现类,维护着自身的状态变量 `state_` 并提供设置状态的方法 `setState()`。每当状态改变时,都会自动触发 `notifyObservers()` 方法向所有已注册的观察者发送消息[^3]。 4. **`ConcreteObserver` 类** 继承自 `Observer` 抽象类的具体实现之一,实现了 `update()` 函数用于处理来自主题的通知信息。此外还包含了两个额外的功能——订阅 (`subscribeToSubject`) 和取消订阅 (`unsubscribeFromSubject`) 主题的操作。 5. **现代特性应用** - 利用了 C++11/14 提供的新特性如智能指针(`std::shared_ptr`, `std::weak_ptr`),可以有效管理动态内存分配的同时防止潜在的悬挂指针问题。 - 使用了范围内的 lambda 表达式简化回调机制的设计思路[^2]。 --- #### 输出示例 假设我们创建如下场景: ```cpp int main() { auto subject = std::make_shared<ConcreteSubject>(); auto obsA = std::make_shared<ConcreteObserver>("A", subject); auto obsB = std::make_shared<ConcreteObserver>("B", subject); obsA->subscribeToSubject(); obsB->subscribeToSubject(); subject->setState("State Changed to X"); obsB->unsubscribeFromSubject(); // B 不再接收后续通知 subject->setState("Another State Change"); } ``` 运行结果将是: ``` Observer A: Received message - State Changed to X Observer B: Received message - State Changed to X Observer A: Received message - Another State Change ``` 这表明只有仍然保持订阅关系的观察者才会接收到最新的状态变更通知。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值