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

来源:互联网 发布:yy频道挂机软件下载 编辑:程序博客网 时间:2024/06/06 17:03
观察者模式

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

  优点:
目标(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);
  ...
}

原创粉丝点击