【问题标题】:generic observer pattern通用观察者模式
【发布时间】:2016-05-11 12:07:28
【问题描述】:

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

一些由观察者实现的接口:

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

但我不确定我是不是在重新发明轮子。有没有更简单、众所周知的方法来做到这一点?

【问题讨论】:

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


【解决方案1】:

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

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

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

监听器现在负责维护std::shared_ptr 的生命周期。

在广播器内部,您在广播前持有weak_ptr.lock()。如果我真的不需要注销(通常我不需要),我会懒洋洋地清理我的weak_ptrs 列表。否则,我返回的shared_ptr 有一个删除功能,用于取消注册。


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

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

根据我的经验,让听众保持std::vector<token> 就足够了。如果他们有更复杂的聆听关系,他们可以做更多的工作,维护钥匙等。

混合模型也是可能的。


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

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

这也不适用于您想要注册听众的情况,并且广播者和听众的生命周期就像爆米花一样。

【讨论】:

  • 完美使用weak_ptr
猜你喜欢
  • 2021-05-08
  • 2016-02-20
  • 2023-04-10
  • 1970-01-01
  • 2014-05-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多