[观察者模式]在游戏开发中的应用

一、观察者模式

定义:定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。

概述:该模式主要有两个角色,主题中心与观察者。观察者可以订阅主题中心。主题中心的状态会发生改变,状态改变时将该事件通知给所有参与订阅的观察者。观察者获知后采取相应的行动。

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的通知中心,还介绍了几种进行两个类之间通信的方案)

作者:唐衣可俊
出处:http://www.cnblogs.com/tangyikejun/
版权:本文版权归作者本人所有
转载:欢迎转载,但未经作者同意,必须保留此段声明;必须在文章中给出原文连接;否则必究法律责任