观察者模式
意图:
定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
结构:
优点:
目标(Subject)与观察者(Observer)间抽象耦合
支持广播通信/通知
缺点:
会带来意外更新问题
示例:
考虑这样一个例子:想知道公司最新的MM情报吗?加入我们MM情报邮件组吧。您只需要向我们发送一封订阅邮件即可,我们会把最新的MM情报以电子邮件形式通知您。
现在我们来一步一步实现。很明显,示例中关心MM情况的人物即为订阅者,我们以Subscriber表示这一类人。在定义Subscriber之前我们先定义一个MMStatus枚举,用以表示MM状态:
enum MMStatus {Dining, Sleeping, Working};
这里定义了三个常量用以简单地模拟MM所处的状态。现在我们可以定义Subscriber类了:
struct Subscriber
{
virtual void action(MMStatus status) = 0;
virtual ~Subscriber() {}
};
有经验的读者知道,这样定义Subscriber表明它是个基类,也是个抽象类,或者称之为接口(java中就有 interface关键字)。之所以这样设计,是因为可能存在很多种类型的订阅者(Subscriber接口的子类),每种订阅者对MM的同一种状态可能会有不同的处理方式。这里把多种类型的订阅者抽象出相同的接口方法,也就是Subscriber定义的第3行。第4行虽然只是个空定义,但这是不可缺少的,防止在用基类指针指向子类而delete基类指针时子类的析构行为能正确调用。我们继续定义我们的目标类。没错,就是MM情报组,我们以 MMIntelligenceAgent类表示。
class MMInteligenceAgent
{
public:
void subscribe(Subscriber &subscriber);
void desubscribe(Subscriber &subscriber);
private:
void notifyAll(MMStatus status);
private:
std::list<Subscriber*> subscribers_;
};
MMInteligenceAgent类有两个公有方法(4、5行),分别用以增加和移除一个订阅者。订阅者可能有多个,我们选择以链表存储之(9行)。当MM状态变更后,借助notifyAll方法,链表中的所有订阅者都会得到通知。
目标类的实现很简单:
void MMInteligenceAgent::subscribe(Subscriber &subscriber)
{
subscribers_.push_back(&subscriber);
}
void MMInteligenceAgent::desubscribe(Subscriber &subscriber)
{
subscribers_.erase(
std::remove(subscribers_.begin(), subscribers_.end(), &subscriber),
subscribers_.end());
}
void MMInteligenceAgent::notifyAll(MMStatus status)
{
for (list<Subscriber*>::iterator it = subscribers_.begin();
it != subscribers_.end(); ++it) {
(*it)->action(status);
}
}
主要的基类及方法都写好了,接下来我们示例个具体Subscriber类:偷窃者。偷窃者一般在偷盗目标熟睡时比较容易下手,于是偷窃者可使用MM情报组提供的服务,以便知道MM何时在睡觉:
struct Larcener : public Subscriber
{
virtual void action(MMStatus status)
{
if (status == Sleeping) {
// steal something ...
}
}
};
为了使代码更完整,我们可以为MMInteligenceAgent增加一个对MM的跟踪方法,当发现MM状态改变时发出通知。
void MMInteligenceAgent::trace()
{
...
MMStatus status = ...;
notifyAll(status);
}
最后以一个调用示例作为此篇的结束:
int main()
{
...
Larcener l;
MMInteligenceAgent mia;
mia.subscribe(l);
mia.trace();
...
mia.desubscribe(l);
...
}
意图:
定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
结构:
优点:
目标(Subject)与观察者(Observer)间抽象耦合
支持广播通信/通知
缺点:
会带来意外更新问题
示例:
考虑这样一个例子:想知道公司最新的MM情报吗?加入我们MM情报邮件组吧。您只需要向我们发送一封订阅邮件即可,我们会把最新的MM情报以电子邮件形式通知您。
现在我们来一步一步实现。很明显,示例中关心MM情况的人物即为订阅者,我们以Subscriber表示这一类人。在定义Subscriber之前我们先定义一个MMStatus枚举,用以表示MM状态:
enum MMStatus {Dining, Sleeping, Working};
这里定义了三个常量用以简单地模拟MM所处的状态。现在我们可以定义Subscriber类了:
struct Subscriber
{
virtual void action(MMStatus status) = 0;
virtual ~Subscriber() {}
};
有经验的读者知道,这样定义Subscriber表明它是个基类,也是个抽象类,或者称之为接口(java中就有 interface关键字)。之所以这样设计,是因为可能存在很多种类型的订阅者(Subscriber接口的子类),每种订阅者对MM的同一种状态可能会有不同的处理方式。这里把多种类型的订阅者抽象出相同的接口方法,也就是Subscriber定义的第3行。第4行虽然只是个空定义,但这是不可缺少的,防止在用基类指针指向子类而delete基类指针时子类的析构行为能正确调用。我们继续定义我们的目标类。没错,就是MM情报组,我们以 MMIntelligenceAgent类表示。
class MMInteligenceAgent
{
public:
void subscribe(Subscriber &subscriber);
void desubscribe(Subscriber &subscriber);
private:
void notifyAll(MMStatus status);
private:
std::list<Subscriber*> subscribers_;
};
MMInteligenceAgent类有两个公有方法(4、5行),分别用以增加和移除一个订阅者。订阅者可能有多个,我们选择以链表存储之(9行)。当MM状态变更后,借助notifyAll方法,链表中的所有订阅者都会得到通知。
目标类的实现很简单:
void MMInteligenceAgent::subscribe(Subscriber &subscriber)
{
subscribers_.push_back(&subscriber);
}
void MMInteligenceAgent::desubscribe(Subscriber &subscriber)
{
subscribers_.erase(
std::remove(subscribers_.begin(), subscribers_.end(), &subscriber),
subscribers_.end());
}
void MMInteligenceAgent::notifyAll(MMStatus status)
{
for (list<Subscriber*>::iterator it = subscribers_.begin();
it != subscribers_.end(); ++it) {
(*it)->action(status);
}
}
主要的基类及方法都写好了,接下来我们示例个具体Subscriber类:偷窃者。偷窃者一般在偷盗目标熟睡时比较容易下手,于是偷窃者可使用MM情报组提供的服务,以便知道MM何时在睡觉:
struct Larcener : public Subscriber
{
virtual void action(MMStatus status)
{
if (status == Sleeping) {
// steal something ...
}
}
};
为了使代码更完整,我们可以为MMInteligenceAgent增加一个对MM的跟踪方法,当发现MM状态改变时发出通知。
void MMInteligenceAgent::trace()
{
...
MMStatus status = ...;
notifyAll(status);
}
最后以一个调用示例作为此篇的结束:
int main()
{
...
Larcener l;
MMInteligenceAgent mia;
mia.subscribe(l);
mia.trace();
...
mia.desubscribe(l);
...
}