设计理念
定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。
我们可以想象订阅报纸的场景,当我们订阅某日报时当天的日报就会准时到达我们手中,而对于我们不关心的报刊只要我们不订阅他们我们就不会受到关于他们的信息。也就是说通过订阅的方式,我们与报刊之间产生了依赖的关系,而且通常是某日报同时发放到多个订阅者手中。当日报发生更新是,订阅者也会得到通知。
将一个系统分割成一个一些类相互协作的类有一个不好的副作用,那就是需要维护相关对象间的一致性。我们不希望为了维持一致性而使各类紧密耦合,这样会给维护、扩展和重用都带来不便。观察者就是解决这类的耦合关系的。
UML类图
图中的角色
- 抽象主题(Subject):它把所有观察者对象的引用保存到一个聚集里,每个主题都可以有任何数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象。
- 具体主题(ConcreteSubject):将有关状态存入具体观察者对象;在具体主题内部状态改变时,给所有登记过的观察者发出通知。
- 抽象观察者(Observer):为所有的具体观察者定义一个接口,在得到主题通知时更新自己
- 具体观察者(ConcreteObserver):实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题状态协调。
实现代码
#include <iostream>
#include "Subject.h"
#include "Obeserver.h"
#include "ConcreteObeserver.h"
#include "ConcreteSubject.h"
using namespace std;
int main(int argc, char *argv[])
{
Subject * subject = new ConcreteSubject();
Obeserver * objA = new ConcreteObeserver("A");
Obeserver * objB = new ConcreteObeserver("B");
subject->attach(objA);
subject->attach(objB);
subject->setState(1);
subject->notify();
cout << "--------------------" << endl;
subject->detach(objB);
subject->setState(2);
subject->notify();
delete subject;
delete objA;
delete objB;
return 0;
}
///////////////////////////////////////////////////////////
// Subject.h
///////////////////////////////////////////////////////////
#include "Obeserver.h"
#include <vector>
using namespace std;
class Subject
{
public:
Subject();
virtual ~Subject();
Obeserver *m_Obeserver;
void attach(Obeserver * pObeserver);
void detach(Obeserver * pObeserver);
void notify();
virtual int getState() = 0;
virtual void setState(int i)= 0;
private:
vector<Obeserver*> m_vtObj;
};
///////////////////////////////////////////////////////////
// Subject.cpp
///////////////////////////////////////////////////////////
#include "Subject.h"
Subject::Subject(){
}
Subject::~Subject(){
}
void Subject::attach(Obeserver * pObeserver){
m_vtObj.push_back(pObeserver);
}
void Subject::detach(Obeserver * pObeserver){
for(vector<Obeserver*>::iterator itr = m_vtObj.begin();
itr != m_vtObj.end(); itr++)
{
if(*itr == pObeserver)
{
m_vtObj.erase(itr);
return;
}
}
}
void Subject::notify(){
for(vector<Obeserver*>::iterator itr = m_vtObj.begin();
itr != m_vtObj.end();
itr++)
{
(*itr)->update(this);
}
}
///////////////////////////////////////////////////////////
// Obeserver.h
///////////////////////////////////////////////////////////
class Subject;
class Obeserver
{
public:
Obeserver();
virtual ~Obeserver();
virtual void update(Subject * sub) = 0;
};
///////////////////////////////////////////////////////////
// ConcreteObeserver.h
///////////////////////////////////////////////////////////
#include "Obeserver.h"
#include <string>
using namespace std;
class ConcreteObeserver : public Obeserver
{
public:
ConcreteObeserver(string name);
virtual ~ConcreteObeserver();
virtual void update(Subject * sub);
private:
string m_objName;
int m_obeserverState;
};
///////////////////////////////////////////////////////////
// ConcreteObeserver.cpp
///////////////////////////////////////////////////////////
#include "ConcreteObeserver.h"
#include <iostream>
#include <vector>
#include "Subject.h"
using namespace std;
ConcreteObeserver::ConcreteObeserver(string name){
m_objName = name;
}
ConcreteObeserver::~ConcreteObeserver(){
}
void ConcreteObeserver::update(Subject * sub){
m_obeserverState = sub->getState();
cout << "update oberserver[" << m_objName << "] state:" << m_obeserverState << endl;
}
总结
观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个目标对象,当这个目标对象的状态发生变化时,会通知所有观察者对象,使它们能够自动更新。
观察者模式的主要优点在于可以实现表示层和数据逻辑层的分离,并在观察目标和观察者之间建立一个抽象的耦合,支持广播通信;其主要缺点在于如果一个观察目标对象有很多直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间,而且如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃
参考链接
http://design-patterns.readthedocs.io/zh_CN/latest/behavioral_patterns/observer.html
http://www.cnblogs.com/wangjq/archive/2012/07/12/2587966.html