Observer模式:多主题观察下避免重复更新及DAGChangeManager实现疑问
DAGChangeManager实现细节疑问解答
场景背景
有向边A→B表示B观察A,即A状态变更时会触发对B的通知。经典观察者模式存在重复更新问题:例如Topbar状态变更后,SecondaryTopbar、Gallery、Toolbar、Captions会收到通知;而SecondaryTopbar因这次通知变更状态后,又会通知Topbar、Gallery、Toolbar、Captions;最终Toolbar会被通知两次,Captions最坏情况会被通知四次。
现有两种ChangeManager实现:
SimpleChangeManager:会直接更新每个主题的所有观察者,无法解决重复通知问题DAGChangeManager:通过维护主题与观察者间的有向无环依赖图,避免观察者因多主题变更收到重复更新,适合观察者同时观察多个主题的场景
本人的场景适合使用DAGChangeManager,但对其实现细节存在以下疑问:
1. 应维护包含所有观察者与主题的单一DAG,还是为每个主题/可观察者维护独立DAG?
必须维护单一全局DAG。
因为观察者和主题的身份是动态交叉的——比如你的场景里,SecondaryTopbar既是Topbar的观察者,又是Gallery、Toolbar等的主题。如果拆分多个独立DAG,根本无法追踪这种跨节点的依赖链,也就没法从根源上解决重复通知的问题。只有全局DAG才能完整映射所有实体(主题和观察者都作为节点)之间的观察关系,确保在处理状态变更时能遍历整个依赖链完成去重。
2. 注册新观察者时如何维护不变性?
这里的不变性核心是保证DAG始终保持无环状态,同时要保证注册操作的原子性:
- 先做环检测:在添加新的观察边(即
主题→观察者的有向边,对应“观察者观察主题”的关系)前,要检查添加这条边后是否会形成环。比如如果要注册B观察A,但A已经观察B,添加边后就会形成A→B→A的环,这种情况必须拒绝。 - 原子化操作:注册过程中要对DAG加锁,避免并发修改导致的不一致——比如正在检测环的过程中,另一个线程添加了新边,导致环检测结果失效。
- 失败回滚:如果检测到添加新边会破坏无环性,直接拒绝本次注册请求,不修改DAG的现有状态。
3. 仅无环性是否能保证每个观察者被通知且仅被通知一次?是否还需要连通性?
仅无环性不足以保证,但连通性完全不需要,核心需要结合拓扑排序+单轮更新标记:
- 无环性是基础:只有DAG无环,才能通过拓扑排序确定通知的顺序,避免出现无限循环的通知链条。
- 单轮去重标记:即便DAG无环,一个观察者可能同时被多个主题的变更路径触发通知。所以必须在单次状态变更的处理流程中,给已通知过的观察者打标记,确保同一个观察者在一轮更新周期里只被通知一次。
- 连通性无关紧要:DAG允许存在多个独立的连通分量,不同分量的状态变更互不干扰——比如系统里完全不相关的模块,它们的依赖链不需要连通,这是合理的设计。
内容的提问来源于stack exchange,提问作者Baffo rasta
相关产品推荐
相关产品推荐

