您的位置:首页 > 编程语言 > C语言/C++

设计模式之观察者(Observer)模式与其C++通用实现(上)

2008-10-11 11:38 555 查看
设计模式之观察者(Observer)模式与其C++通用实现分上、中、下三篇。上篇详细讲解何为观察者模式以及其特点,并给出一个应用实例与其实现。中篇研究如何运用C++各种技术实现一个通用/万能的观察者模式。下篇讨论中篇所给出的实现可能遇到的问题及解决方案。

设计模式之观察者(Observer)模式与其C++通用实现(上)
[/b] ——林石 [/b]2008-09-30
[/b]
观察者模式[/b]

意图

定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
结构



优点

目标(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);
...
}
<未完,待续>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐