模式动机
建立一种对象与对象之间的依赖关系,一个对象发生改变时将自动通知其他对象,其他对象将相应做出反应。在此,发生改变的对象称为观察目标,而被通知的对象称为观察者,一个观察目标可以对应多个观察者,而且这些观察者之间没有相互联系,可以根据需要增加和删除观察者,使得系统更易于扩展,这就是观察者模式的模式动机。
模式定义
观察者模式:定义对象间的一种一对多依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象皆得到通知并被自动更新。观察者模式又叫做发布-订阅模式、模型-视图模式、源-监听器模式或从属者模式。观察者模式是一种对象行为型模式。
观察者模式适用情况
(1)当一个对象的数据更新时需要通知其他对象,但这个对象又不希望和被通知的那些对象形成紧耦合。
(2)当一个对象的数据更新时,这个对象需要让其他对象也各自更新自己的数据,但这个对象不知道具体有多少对象需要更新数据。
观察者模式的优点
(1)具体主题和具体观察者是松耦合关系。由于主题接口仅仅依赖于观察者接口,因此具体主题只是知道它的观察者是实现观察者接口的某个类的实例,但不需要知道具体是哪个类。同样,由于观察者仅仅依赖于主题接口,因此具体观察者只是知道它依赖的主题是实现主题接口的某个类的实例,但不需要知道具体是哪个类。
(2)观察者模式满足“开-闭原则”。主题接口仅仅依赖于观察者接口,这样,就可以让创建具体主题的类也仅仅是依赖于观察者接口,因此,如果增加新的实现观察者接口的类,不必修改创建具体主题的类的代码。。同样,创建具体观察者的类仅仅依赖于主题接口,如果增加新的实现主题接口的类,也不必修改创建具体观察者类的代码。
观察者模式UML图:
C++的实现:
#include <iostream>
#include <list>
using namespace std;
class Observer
{
public:
virtual void Update(int) = 0;
};
class Subject
{
public:
virtual void Attach(Observer *) = 0;
virtual void Detach(Observer *) = 0;
virtual void Notify() = 0;
};
class ConcreteObserver : public Observer
{
public:
ConcreteObserver(Subject *pSubject) : m_pSubject(pSubject){}
void Update(int value)
{
cout << "ConcreteObserver get the update. New State:" << value << endl;
}
private:
Subject *m_pSubject;
};
class ConcreteObserver2 : public Observer
{
public:
ConcreteObserver2(Subject *pSubject) : m_pSubject(pSubject){}
void Update(int value)
{
cout << "ConcreteObserver2 get the update. New State:" << value << endl;
}
private:
Subject *m_pSubject;
};
class ConcreteSubject : public Subject
{
public:
void Attach(Observer *pObserver);
void Detach(Observer *pObserver);
void Notify();
void SetState(int state)
{
m_iState = state;
}
private:
std::list<Observer *> m_ObserverList;
int m_iState;
};
void ConcreteSubject::Attach(Observer *pObserver)
{
m_ObserverList.push_back(pObserver);
}
void ConcreteSubject::Detach(Observer *pObserver)
{
m_ObserverList.remove(pObserver);
}
void ConcreteSubject::Notify()
{
std::list<Observer *>::iterator it = m_ObserverList.begin();
while (it != m_ObserverList.end())
{
(*it)->Update(m_iState);
++it;
}
}
int main()
{
// Create Subject
ConcreteSubject *pSubject = new ConcreteSubject();
// Create Observer
Observer *pObserver = new ConcreteObserver(pSubject);
Observer *pObserver2 = new ConcreteObserver2(pSubject);
// Change the state
pSubject->SetState(2);
// Register the observer
pSubject->Attach(pObserver);
pSubject->Attach(pObserver2);
pSubject->Notify();
// Unregister the observer
pSubject->Detach(pObserver);
pSubject->SetState(3);
pSubject->Notify();
delete pObserver;
delete pObserver2;
delete pSubject;
}
在cocos2dx中的应用:
观察者模式被广泛应用于游戏引擎的事件系统,比如在cocos2dx中:
EventListener类相当于观察者:EventListener保存了收到主题类通知后的回调update(事件回调函数)
EventDispatcher类相当于主题/观察目标:EventDispatcher中有个容器std::unordered_map<EventListener::ListenerID, EventListenerVector*> _listenerMap保存了所有的观察者EventListener,dispatchEvent()函数相当于notify()通知
关于事件的分析可以参考:cocos2dx之event事件(三):事件分发器EventDispatcher