[观察者模式]在游戏开发中的应用
一、观察者模式
定义:定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。
概述:该模式主要有两个角色,主题中心与观察者。观察者可以订阅主题中心。主题中心的状态会发生改变,状态改变时将该事件通知给所有参与订阅的观察者。观察者获知后采取相应的行动。
1、核心思想
弱化两个对象的耦合关系。观察者仅在某条件满足时(主题中心状态改变)参与活动。
2、类图
- 抽象主题(Subject):它把旗下所有观察者对象的引用保存到一个序列里面,每个主题中心都可以有任何数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象。
- 具体主题(ConcreteSubject):具体主题持有状态,当内部状态改变时,向所有观察者发出通知。同时向观察者提供用于查询状态的接口。
- 抽象观察者(Observer):为所有的具体观察者定义一个接口,在得到主题中心通知时更新自己。
- 具体观察者(ConcreteObserver):持有具体主题的引用。实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题中心状态协调。
3、基本代码
////主题中心//////////////////////////////////////
// 主题中心
class Subject{
list<Observer* > _observers;
public:
void Attach(Observer *observer); // 添加观察者
void Detach(Observer *observer); // 移除观察者
protected:
void Notify(){ // 通知所有观察者
// 遍历观察者
list<Observer*>::iterator iter;
for(iter = _observers.begin(); iter != _observers.end(); iter++)
(*iter)->Update();
};
};
// 具体主题
class ConcreteSubject: public Subject{
State _state;//状态
public:
ConcreteSubject();
~ConcreteSubject();
public:
void SetState(State state){ // 设置状态
_state = state;
Notify();
};
State GetState(){return _state;}; // 获取状态
};
////观察者//////////////////////////////////////
class Observer{
public:
virtual void Update()=0;
};
// 具体观察者
class ConcreteObserver: public Observer{
ConcreteSubject *_subject;// 具体主题对象
public:
ConcreteObserver(ConcreteSubject *subject): _subject(subject) {};
~ConcreteObserver();
public:
virtual void Update(){ //更新
State state = _subject->GetState();
//do something
};
};
////客户端//////////////////////////////////////
...
ConcreteSubject *subject = new ConcreteSubject();
Observer *observer = new ConcreteObserver(subject);
subject.Attach(observer);
subject.setState(state);
subject.Dettach(observer);
...
5、应用场景以及优缺点
1)应用场景
- 当一个对象的改变需要给变其它对象时,而且它不知道具体有多少个对象有待改变时。
- 有依赖关系的双方都是易变体,需要封装变化达到各自独立改变的目的。
2)优点
采用该模式可以方便地更换算法或者增加新的算法。避免了较难维护的多重选择条件选择语句。
3)缺点
订阅后如果不进行取消订阅操作容易引起内存泄露
二、游戏应用
1、适用场景
- 事件分发管理器。当用户进行触摸、按键等输入后,输入管理类将事件分发给添加了事件监听的对象。
- 游戏业务逻辑与游戏控制器。当游戏业务逻辑改变了自身状态后,将该变化通知给添加了监听的控制器。
2、具体案例
俄罗斯方块游戏中消除满行是一个重要并且激动人心的事件。我们希望在消除满行的时候能够采用动画的方式展示并进行加分。按照 MVC 的架构模式,动画显示是视图层的职责,加分是 模型层中 成就系统的一部分,消除满行是模型层中游戏机制系统的一部分。而控制层负责选择视图、选择模型。因此,可以让控制层通过观察者模式监听模型层中的游戏机制系统。
1)伪代码
////主题中心//////////////////////////////////////
class Model{ // 模型层
Attach(Controller);
Detach(Controller);
Notify();
};
class Gamplay: Model{ // 游戏机制
消除满行(){
数据加工();
Notify();
}
};
class Achievement: Model{
添加分数();
};
////观察者//////////////////////////////////////
class IController{
满行消除();
等级提升();
};
class Controller: IController{
满行消除(){
view->消行动画();
achievement->添加分数();
}
};
////客户端//////////////////////////////////////
...
gameplay->Attach(Controller);
...
gamplay->消除满行();
...
三、参考
C++设计模式-Observer观察者模式(参考了该文的观察者模式C++实现方式)
设计模式学习笔记-观察者模式(参考了该文的观察者模式C++实现方式)
Cocos2d-x观察者模式(介绍了Cocos2d-x的通知中心,还介绍了几种进行两个类之间通信的方案)