我正在处理代码,其中有很多观察者模式实现。所有这些都是以这样的方式组织的:
观察者要实现的一些接口(interface):
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();
}
}
};
每次都有Register和Unregister的复制粘贴以及ObserverInterface的每个方法的通知实现。并且每次程序员必须记住调用 Unregister() 时,如果它的观察者将被销毁。
我希望将观察者模式包含在两个类模板中。到目前为止,我有类似的东西: http://rextester.com/UZGG86035
但我不确定我是不是在重新发明轮子。有没有更简单、广为人知的方法来做到这一点?
最佳答案
在 C++11 中,我建议使用基于标记的方法。
你注册了一个观察者。观察者只是一个 std::function<void(Signature...)>
.
注册函数返回一个 token ,std::shared_ptr<void>
.只要返回 shared_ptr
有效,广播者将继续向该听众广播。
监听器现在负责维护 std::shared_ptr
生命周期。
在广播公司内部,你拿着一个 weak_ptr
和 .lock()
它在广播之前。如果我真的不需要取消注册(通常我不需要),我会懒惰地清理我的 weak_ptr
列表。秒。否则,我 shared_ptr
I return 有一个删除功能,可以完成注销。
或者,您的听众是 shared_ptr<std::function<void(Args...)>>
,并在内部存储 weak_ptr
相同。
在此模型中,您无法轻易地注入(inject)取消注册功能。然而,这确实意味着它们可以使用别名构造函数自己将回调的生命周期紧密绑定(bind)到它们自己,假设它们由 shared_ptr 管理。
根据我的经验,只需让听众维护一个 std::vector<token>
足够了。如果他们有更复杂的倾听关系,他们可以做更多的工作,维护 key 等。
混合模型也是可能的。
这两者对于非线程安全的广播都是可以接受的,并且可以用几十行代码编写。
线程安全广播变得棘手。通常,我发现您最好为此使用消息传递模式而不是替代方案,因为这会稍微降低推理并发性的难度。
这也不处理您想注册听众的情况,广播者和听众的生命周期就像爆米花。
关于c++ - 通用观察者模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35157655/