意图:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
动机:将一个系统分割成一系列相互协作的类有一个副作用:需要维护相关对象间的一致性。不希望为了维持一致性而使各类紧密耦合,这样会降低可重用性。
Observer模式中的关键对象是目标(subject)和观察者(observer).一个目标可以有任意数目的依赖它的观察者。一旦目标的状态发生改变,所有的观察者都得到通知。作为对这个通知的响应,每个观察者都将查询目标以使其状态与目标的状态同步。
这种交互也称为“发布-订阅”。目标是通知的发布者。它发出通知时并不需要知道谁是它的观察者。可以有任意数目的观察者订阅并接收通知。
适用性:
1 当一个抽象模型有两个方面,其中一个方面依赖于另一个方面。这二者封装在独立的对象中以使它们可以各自独立地改变和复用。
2 当对一个对象的改变需要同时改变其它对象,而不知道具体有多少对象有待改变。
3 当一个对象必须通知其它对象,而它又不能假定其它对象是谁。即不希望对象是紧密耦合的
结构:
参与者:
Subject(目标):
1 目标知道它的观察者。可以有任意多个观察者观察同一个目标。
2 提供注册和删除观察者对象的接口。
Observer(观察者):
为那些在目标发生改变时许获得通知的对象定义一个更新接口。
ConcreteSubject(具体目标):
1 将有关状态存入各ConcreteObserver对象。
2 当它的状态发生改变时,向它的各个观察者发出通知。
ConcreteObserver(具体观察者):
1 维护一个指向ConcreteSubject对象的引用
2 存储有关状态,这些状态应与目标的状态保持一致。
3 实现Observer的更新接口以使自身状态与目标的状态保持一致。
协作:
当ConcreteSubject发生任何可能导致其观察者与其本身状态不一致的改变时,它将通知它的各个观察者。
在得到一个具体目标的改变通知后,ConcreteObserver对象可向目标对象查询信息。ConcreteObserver使用这些信息以使它的状态与目标对象的状态一致。
如下图说明了一个目标对象和两个观察者之间的协作:
发出改变请求的Observer对象并不立即更新,而是将其推迟到它从目标得到一个通知之后。Notify不总是由目标对象调用。也可被一个观察者或其它对象调用。
效果:
1 目标与观察者之间的抽象耦合。
2 支持广播通信:可以广播给所有已向该目标对象登记的有关对象。
3 意外的更新
实现:
1 创建目标到其观察者之间的映射
2 观察多个目标:一个观察者依赖于多个目标。
3 谁触发更新。
A 由目标对象的状态设定操作在改变目标对象的状态后自动调用Notify
B 由客户负责在适当的时候调用Notify
4 对已删除目标的悬挂引用:删除一个目标时不应遗留对该目标的悬挂引用
5 在发出通知前确保目标的状态自身是一致的
6 避免特定于观察者的更新协议----推/拉模型
推模型(push model):目标向观察者发生关于改变的详细信息,而不管它们是否需要
拉模型(pull model):目标除最小通知外什么也不送出,这之后由观察者显示向目标询问
7 显示的指定感兴趣的改变
8 封装复杂的更新语义:当目标和观察者间的依赖关系特别复杂时,使用ChangeManager来维护这些关系。目标是尽量减少观察者反应器目标的状态变化所需的工作量。
9 结合目标类和观察者类
相关模式:
Mediator:通过封装复杂的更新语义,ChangeManager充当目标和观察者之间的中介者。
Siglenton:ChangeManager可使用Singleton模式来保证它是唯一的并且是可全局访问的。
代码如下:
//观察者模式
#include <iostream>
#include <list>
#include <algorithm>
using namespace std;
class Subject;
//抽象观察者
class Observer
{
public:
Observer(string name, Subject* sub)
: _name(name), _sub(sub)
{
}
virtual void Update() = 0;
protected:
string _name;
Subject* _sub;
};
//通知者接口
class Subject
{
public:
//增加
virtual void Attach(Observer& observer)
{
observers.push_back(&observer);
}
virtual void Detach(Observer& observer)
{
observers.remove(&observer);
}
virtual void Notify()
{
//通知每一个观察者
for_each(observers.begin(), observers.end(), mem_fun(&Observer::Update));
}
//状态
virtual string GetSubjectState()
{
return action;
}
virtual void SetSubjectState(string value)
{
action = value;
}
protected:
list<Observer*> observers;
string action;
};
//具体通知者
class Boss : public Subject
{
};
//前台秘书类
class Secretary : public Subject
{
};
//看股票的同事
class StockObserver : public Observer
{
public:
//设置通知者
StockObserver(string name, Subject* sub)
: Observer(name, sub)
{
}
void Update()
{
cout << _sub->GetSubjectState() << _name << "关闭股票行情,继续工作" << endl;
}
};
//看NBA的同事
class NBAObserver : public Observer
{
public:
NBAObserver(string name, Subject* sub)
: Observer(name, sub)
{
}
void Update()
{
cout << _sub->GetSubjectState() << _name << "关闭NBA直播,继续工作!" << endl;
}
};
int main()
{
//目标,通知者
Boss huhansan;
//看股票的同事
StockObserver tongshi1("魏关宅", &huhansan);
//看NBA的同事
NBAObserver tongshi2("易管查", &huhansan);
huhansan.Attach(tongshi1);
huhansan.Attach(tongshi2);
//huhansan.Detach(tongshi1);
huhansan.SetSubjectState("我胡汉三回来了!");
huhansan.Notify();
system("pause");
return 0;
}