Pat*_*ick 4 c++ language-agnostic design-patterns observer-pattern
在我的应用程序中,我有很多课程.这些类中的大多数存储了相当多的数据,如果其中一个数据类的内容发生变化,我的应用程序中的其他模块也会"更新".
这样做的典型方法是这样的:
void MyDataClass::setMember(double d)
{
m_member = d;
notifyAllObservers();
}
Run Code Online (Sandbox Code Playgroud)
如果不经常更改成员并且"观察类"需要尽可能快地更新,这是一个非常好的方法.
另一种观察变化的方法是:
void MyDataClass::setMember(double d)
{
setDirty();
m_member = d;
}
Run Code Online (Sandbox Code Playgroud)
如果成员多次更改,这是一个很好的方法,并且"观察类"会在所有"脏"实例中定期查看.
不幸的是,我的课程中混合了两种数据成员.有些是经常改变的(并且我可以和普通的观察者一起生活),其他的被改变很多次(这是在复杂的数学算法中)并且每当值改变时调用观察者将会破坏我的应用程序的性能.
是否还有其他观察数据变化的技巧,或者您可以轻松组合几种观察数据变化的不同方法的模式?
虽然这是一个与语言无关的问题(我可以尝试理解其他语言中的示例),但最终的解决方案应该适用于C++.
你所描述的两种方法涵盖(概念上)两个方面,但我认为你没有充分解释它们的优点和缺点.
您应该注意一个项目,这是人口因素.
如果你有许多通知者,你的观察者应该遍历它们中的每一个来发现2或3 dirty......它将无法工作.另一方面,如果你有很多观察者,并且在每次更新时都需要通知他们所有人,那么你可能注定要失败,因为简单地遍历所有这些会破坏你的表现.
然而,有一种可能性你没有谈到:将两种方法结合起来,与另一种间接方式相结合.
GlobalObserverGlobalObserver何时需要但这并不容易,因为每个观察者都需要记住它最后一次检查的时间,仅通知它尚未观察到的变化.通常的技巧是使用时代.
Epoch 0 Epoch 1 Epoch 2
event1 event2 ...
... ...
Run Code Online (Sandbox Code Playgroud)
每个观察者都记得它需要阅读的下一个时期(当观察者订阅它时,它被给予当前时期),并从该时期读取到当前时期以了解所有事件.通常,通知器不能访问当前时期,例如,每当读取请求到达时(例如,当前时期不为空),您可以决定切换时期.
这里的困难是知道何时丢弃时期(当不再需要它们时).这需要某种引用计数.请记住,GlobalObserver是将当前时期返回给对象的那个.因此,我们为每个时期引入一个计数器,它只计算有多少观察者尚未观察到这个时代(以及后来的时期).
也可以将它与超时结合起来,记录我们最后一次修改时期(即创建下一个时期)并确定在一定时间后我们可以丢弃它(在这种情况下我们收回计数器并将其添加到下一个时代).
请注意,该方案可扩展为多线程,因为一个纪元可以进行写入(在堆栈上进行推送操作),而其他时期是只读的(原子计数器除外).在不需要分配内存的情况下,可以使用无锁操作来推送堆栈.在堆栈完成时决定切换纪元是完全理智的.