通用观察者模式

时间:2016-02-02 15:38:44

标签: c++ c++11 observer-pattern

我正在使用代码,它有很多观察者模式实现。所有这些都是以这样的方式组织的:

观察员要实现的一些界面:

class ObserverInterface {
  virtual void FooOccurs() = 0;
};

一些实现注册,取消注册和通知的类:

class ObservableImpl {
  public:
    Register(ObserverInterface *observer);
    Unregister(ObserverInterface *observer);

  private:
    void SomeMethod() {
      // foo things
      for(auto &observer: observers) {
        observer.FooOccurs();
      }
    }
};

每次有注册和取消注册的复制粘贴以及ObserverInterface的每个方法的通知实现。每当程序员必须记住调用Unregister()时,如果它的观察者将被破坏。

我希望将观察者模式包含在两个类模板中。到目前为止,我有类似的东西: http://rextester.com/UZGG86035

但我不确定我是不是要重新发明轮子。是否有更容易,众所周知的方法来做到这一点?

1 个答案:

答案 0 :(得分:6)

在C ++ 11中,我建议采用基于令牌的方法。

您注册观察员。观察者只是std::function<void(Signature...)>

注册函数返回一个令牌std::shared_ptr<void>。只要返回shared_ptr有效,广播公司就会继续向该听众广播。

听众现在负责维持std::shared_ptr有效期。

在广播公司内部,您在广播前持有weak_ptr.lock()广告。如果我真的不需要取消注册(通常我不注册),我会懒得清理weak_ptr的列表。否则,我返回的shared_ptr有一个删除功能,可以取消注册。

或者,您的听众是shared_ptr<std::function<void(Args...)>>,在内部将weak_ptr存储到同一个。

在此模型中,您无法轻松注入unregistraiton函数。但是,它确实意味着他们可以使用别名构造函数本身将回调的生命周期紧密绑定到自身,假设它们由shared_ptr管理。

根据我的经验,只需让听众保持std::vector<token>即可。如果他们有更复杂的倾听关系,他们可以做更多的工作,维护密钥等。

混合模型也是可能的。

这两种方法都适用于非线程安全的广播,并且可以用几十行代码编写。

线程安全广播变得棘手。通常我发现你最好使用消息传递模式而不是替代方案,因为这会减少稍微推理并发性的难度。

这也不涉及你想要无限注册听众的情况,而播音员和听众的生命就像爆米花一样。