设计模式中的每一个模式描述了一个在我们周围不断重复发生的问题,以及该问题的解决方案的核心。这样,你就能一次又一次地使用该方案而不必做重复劳动。
设计模式在类间关系这个粒度上给出常见问题的解决方案。属于软件工程中逻辑架构设计中相当重要的一环。
快速查阅各类设计模式使用场景可参考此文:设计模式大全。
一、观察者模式
定义:定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。
概述:该模式主要有两个角色,主题中心与观察者。观察者可以订阅主题中心。主题中心的状态会发生改变,状态改变时将该事件通知给所有参与订阅的观察者。观察者获知后采取相应的行动。
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的通知中心,还介绍了几种进行两个类之间通信的方案)