在实践中,观察者模式的实现如何避免由于重入导致的不良行为?
为了澄清“不良行为”,请考虑模式中的 Subject 在单线程同步实现中具有方法 MethodA() 和 MethodB()、事件 OnMethodA() 和 OnMethodB() 以及一个或多个观察者的情况:
- Subject.MethodA() 被调用,
- Subject 做了它对 MethodA() 所做的事情,然后为所有 Observers 调用 OnMethodA(),
- Observer1 获取 OnMethodA() 事件,并调用 Subject.MethodB(),
- Subject 做了它对 MethodB() 所做的事情,然后为所有 Observers 调用 OnMethodB(),
此时,我们正在为所有观察者调用 OnMethodB(),即使我们仍处于 OnMethodA() 通知的中间。这意味着列表中 Observer1 之后的任何观察者都会在“OnMethodA()”之前看到“OnMethodB()”——这是不好的行为。
- Observer2(由对 Observer1 一无所知的开发人员编写)获取 OnMethodB() 事件,并调用 Subject.MethodA(),
- …永远。Subject.MethodA() -> Observer.OnMethodA() -> Subject.MethodB() -> Observer.OnMethodB() -> Subject.MethodA() -> 等等……</li>
现在你要溢出堆栈了。那是不好的行为。
如果您从一开始就设计了异步的、基于队列的通知,或者在通知期间对 Subject 的调用抛出异常,您可以避免这种情况,这很容易理解。困扰我的是,我几乎从未将其视为实现该模式的最佳(或真正唯一)实践。你必须已经意识到这个问题,才能谷歌“观察者模式可重入”,并且该搜索的结果似乎只是遇到问题的人,而不是一本关于模式的书中的警告。
所以我错过了什么吗? 在实践中,观察者模式的实现如何避免由于重入导致的不良行为?