[设计模式]行为模式-观察者(C++描述)
second60 20180514
1. 什么是观察者模式
打个比方,一个表演者在台上表演,台下有很多观众在观看。当台上的表演者,每做一个动作,台下的观众都可以看到。这里的观众就是观察者。
定义对象间一对多的依赖,当(表演者)一个对象状态改变时,所有依赖它的对象(观众)都得到通知并更新。
观察都模式解决的问题:建立一个Subect对多个Observer的依赖关系,当subject变化时,依赖subject的观察都都会同步改变.
2. 观察都模式结构图
分析:
1. Subject: 主题,需要观察都订阅的主题抽象类,里面包含需要通知的观察都列表
2. ConcretetSubject: 具体主题
3. Observer: 观察者抽象父类,包含通知更新的方法
4. ConcreteObserverA/ConcreteObserverB: 具体的观察都
代码:
#include "stdafx.h"
#include <string>
#include <list>
#include <iostream>
using namespace std;
typedef string State;
class Subject;
// 观察都父类
class Observer
{
public:
Observer(){ _state = ""; }
~Observer(){}
virtual void update(Subject* sub) = 0;
State _state;
};
// 主题抽象父类,只包含观察者和观察者的方法
// 具体的数据是放在实现类中
// 这里的State可以是一个模型的父类,具本什么模型,由子类去决定和操作
class Subject
{
public:
Subject(){ _obverser = new std::list < Observer* > ; }
~Subject(){ /*释放obverser*/ }
virtual void attach(Observer* obv){
_obverser->push_front(obv);
}
virtual void detach(Observer* obv){
if (obv != NULL) _obverser->remove(obv);
}
virtual void notify()
{
std::list<Observer*>::iterator iter = _obverser->begin();
for (; iter != _obverser->end(); ++iter)
{
(*iter)->update(this);
}
}
virtual void setState(const State &st) = 0;
virtual State getState() = 0;
private:
std::list<Observer*> *_obverser;
};
class ConcreteSubject : public Subject
{
public:
ConcreteSubject(){}
~ConcreteSubject(){}
State getState(){ return _state; }
void setState(const State& state){ _state = state; }
protected:
State _state;
};
class ObserverA : public Observer
{
public:
ObserverA(Subject *sub)
{
_sub = sub;
_sub->attach(this);
}
~ObserverA()
{
_sub->detach(this);
if (_sub) delete _sub;
}
void update(Subject* sub)
{
_state = sub->getState();
std::cout << "ObserverA::state=" << _state << std::endl;
}
private:
Subject *_sub;
};
class ObserverB : public Observer
{
public:
ObserverB(Subject *sub)
{
_sub = sub;
_sub->attach(this);
}
~ObserverB()
{
_sub->detach(this);
if (_sub) delete _sub;
}
void update(Subject* sub)
{
_state = sub->getState();
std::cout << "ObserverB::state=" << _state << std::endl;
}
private:
Subject *_sub;
};
int _tmain(int argc, _TCHAR* argv[])
{
// 主题
ConcreteSubject *sub = new ConcreteSubject();
// 观察者监主题
Observer* observer1 = new ObserverA(sub);
Observer* observer2 = new ObserverB(sub);
// 主题修改,通知所有观察都
sub->setState("old");
sub->notify();
// 主题修改,通知所有观察都
sub->setState("new");
sub->notify();
getchar();
return 0;
}
3. 观察者模式用途
观察都模式,我们平时很常用,MVC(model/view/control)模式,一说大家都用过吧。
其实他就是观察都模式的一种。
model: 就是上面的subject
view: 就是上面的观察都,可能有多个不同的观察者
observer模式,也称为发布-订阅模式,目前很多系统都运用了这种模式,如kfak,redis等,只需向系统订阅需要监听的信息,发送信息的只管发送。订阅都只接收自已感兴趣的信息。
适用场景:
1. 一对多依赖,如果一改变,需要通知到多的场景,双方无须了解对方细节
2. MVC场景
3. 订阅 - 发布场景
4. 举例子
观察者模式中MVC是一种非常常用的例子。举个客户端的例了。代码就不写了。
如游戏客户端中的玩家金币信息, 当服务端推送来玩家金币信息时,客户端要通知很多view中有金币相关的界面。如大厅/个人信息/游戏玩家信息等。所以只需监听玩家需要监听的信息,并通知相关的view即可。
分析:
当服务端推送的玩家金币改变时,会自动通知监听的view更新玩家金币信息.
这里只是单个例子,实际运用中,包括很多玩家属性要通知的,这里就列举了。
5. 优缺点
5.1 优点
1. 观察者和主题之间是松耦合,观察都新加删除逻辑,无需改动主题类。
2. 主题只需通知观察者,至于观察者后面想做什么,主题无须了解细节。
3. 只要订阅主题的观察者,都会实时的通知到(主题主动通知,观察都只需等待被更新即可)。如果观察者主动获取,确定不准备时机,而且不能确保有所以观察者都会及时更新。造成信息不同步问题。
4. 符合面向对象开放-封闭原则,有良好的扩展性和维护性
5.2 缺点
1. 观察删除问题,如果主题删除,相应的观察都也要一并删除;
2. 如果是用指针来维护数据,要记得多引用时指针的释放问题
6. 总结
观察者模式,是一个很好的设计模式,符合面向对象开放-封闭原则,有良好的维护和扩展性,现实中运用非常广泛,大系统或框架设计时,或多或少都会用到,所以要善于运用。
7. 后话
设计模式还有五六个,坚持写完所有的,加油。