观 察 者 模 式

我的世界中有一种叫做"观察者"的方块,当它所观察的对象发生变化时,另一端的对象就会响应这个变化。那么在我们的程序设计中,观察者模式(Observer)就是这样一种行为型模式,定义了一种一对多的依赖关系,当一个对象的状态发生改变时,其所有依赖者都会收到通知并自动更新。


认识观察者

观察者模式解决的是一个对象状态改变时,如何自动通知其他依赖对象的问题,同时保持对象间的低耦合和高协作性。

观察者模式包含以下四个角色:

**1、主题:**即"被观察者",是具有状态的对象,其维护着一个观察者列表,提供添加、删除、更新观察者的方法。

**2、观察者:**接受主题的通知,实现自定义的更新方法。当收到通知时,调用更新方法。

**3、具体主题:**主题的具体实现类,在状态改变时通知观察者。

**4、具体观察者:**观察者的具体实现类,定义在收到更新时的具体操作。

观察者模式适合用在需要降低对象间耦合度的场景,不需要知道主题变化的细节。

接下来就以游戏中"暂停与继续"为例,用C++模拟其观察者模式的实现!

实现与总结

观察者模式的实现可以分为四步(主题接口和具体主题可以放在一起,但分离后更有灵活性与扩展性):

1、定义观察者接口:包含更新方法。即"暂停"更新方法与"继续"更新方法。

2、创建具体观察者:观察者接口的具体实现,定义具体行为。比如UI系统在暂停时显现游戏菜单,继续时消失,音乐系统暂停时音乐停止播放,继续游戏后接着播放。

3、定义主题接口:包括删除、添加、通知观察者的方法。就是通知游戏暂停和继续的接口。

4、创建具体主题:实现通知接口,状态改变时通知观察者。这样一来,主题接口负责观察者管理,游戏状态管理器这个具体主题负责游戏状态的管理,职责清晰。

cpp 复制代码
#include <iostream>
using namespace std;
#include <vector>

//观察者接口
class Observer {
public:
	virtual void pauseUpdate() = 0;
	virtual void resumeUpdate() = 0;
	virtual ~Observer(){}
};
//具体观察者------UI系统
class UI : public Observer {
public:
	void pauseUpdate() override {
		cout << "弹出游戏菜单窗口" << endl;
	}
	void resumeUpdate() override {
		cout << "关闭游戏菜单窗口" << endl;
	}
};
//具体观察者------音乐系统
class Music : public Observer {
public:
	void pauseUpdate() override {
		cout << "暂停播放音乐" << endl;
	}
	void resumeUpdate() override {
		cout << "继续播放音乐" << endl;
	}
};
//具体观察者------物理系统
class Physics : public Observer {
public:
	void pauseUpdate() override {
		cout << "禁用物理模拟" << endl;
	}
	void resumeUpdate() override {
		cout << "启用物理模拟" << endl;
	}
};
//主题接口
class Subject {
private:
	//维护观察者列表
	vector<Observer*> observers;
public:
	//添加观察者
	virtual void addObserver(Observer* observer) {
		observers.push_back(observer);
	}
	//删除观察者
	virtual void removeObserver(Observer* observer) {
		observers.erase(
			remove(observers.begin(),observers.end(),observer),observers.end()
		);
	}
	//依次通知观察者游戏暂停
	virtual void notifyPause() {
		for (auto observer : observers) {
			observer->pauseUpdate();
		}
	}
	//依次通知观察者游戏继续
	virtual void notifyResume() {
		for (auto observer : observers) {
			observer->resumeUpdate();
		}
	}
	virtual ~Subject() {};
};
//具体主题------游戏状态管理器
class GameStateManager : public Subject {
private:
	bool isPause = false;//标记是否已经暂停
	void pauseGame() {
		if (!isPause) {
			isPause = true;
			cout << "游戏暂停!" << endl;
			notifyPause();
		}
	}
	void resumeGame() {
		if (isPause) {
			isPause = false;
			cout << "游戏继续!" << endl;
			notifyResume();
		}
	}
public:
	//开关式的转换
	void change() {
		if (isPause) {
			resumeGame();
		}
		else {
			pauseGame();
		}
	}
};
int main() {
	//创建游戏状态管理器
	GameStateManager manager;
	//创建系统
	UI ui;
	Music music;
	Physics physics;

	//注册观察者(注意这个说法)
	manager.addObserver(&ui);
	manager.addObserver(&music);
	manager.addObserver(&physics);

	//玩家开始切换游戏状态
	manager.change();
	manager.change();
	manager.change();
	manager.change();

	return 0;
}

观察者模式的核心在于维护观察者列表,各个观察者之间可以独立变化,自然支持事件处理,非常适合游戏中各种事件系统,一对多通知,不需要不断检测状态,避免轮询开销。但因为其遍历通知的方式,当观察者过多时可能速度较慢,且观察者只能检测到变化,而不知道是如何变化的。


小结

观察者模式特别适合游戏开发,因为游戏本质上就是由大量相互关联但又需要保持独立性的系统组成,通过事件驱动的方式协调运作。

如有补充纠正,欢迎留言。

相关推荐
小陈phd32 分钟前
TensorRT 入门完全指南(一)——从核心定义到生态工具全解析
人工智能·笔记
是上好佳佳佳呀39 分钟前
【前端(十一)】JavaScript 语法基础笔记(多语言对比)
前端·javascript·笔记
handler011 小时前
Linux 内核剖析:进程优先级、上下文切换与 O(1) 调度算法
linux·运维·c语言·开发语言·c++·笔记·算法
其实防守也摸鱼2 小时前
CTF密码学综合教学指南--第四章
网络·笔记·安全·网络安全·密码学·ctf
05候补工程师4 小时前
【ROS 2 具身智能】Gazebo 仿真避坑指南:从“幽灵机器人”到传感器数据流打通
人工智能·经验分享·笔记·ubuntu·机器人
chushiyunen4 小时前
pandas使用笔记、数据清洗、json_normalize
笔记·pandas
HERR_QQ4 小时前
端到端课程自用 4 规划 基于自规划AR的端到端规划 AI 笔记
人工智能·笔记·自动驾驶·transformer
二哈赛车手4 小时前
新人笔记---实现简易版的rag的bm25检索(利用ES),以及RAG上传时的ES与向量数据库双写
java·数据库·笔记·spring·elasticsearch·ai
qiaozhangchi4 小时前
求解器学习笔记
笔记·python·学习
不会编程的懒洋洋5 小时前
C# P/Invoke 基础
开发语言·c++·笔记·安全·机器学习·c#·p/invoke