在大型软件系统中,观察者模式(Observer Pattern)是一种非常常用的设计模式,用于对象之间的一对多依赖 关系。Chromium 的 base
库提供了 ObserverList
与 ObserverListThreadSafe
两种实现,它们在浏览器内核的事件订阅、异步消息处理、模块解耦中被广泛使用。本文将从概念、源码、用法、对比及常见坑等角度,全面解析 Chromium 中 Observer 模式的实现。
一、Observer 模式概念回顾
Observer 模式,又称发布-订阅模式,核心思想是:
-
Subject(被观察者):维护一个观察者列表,当自身状态改变时,通知所有观察者。
-
Observer(观察者):定义一个接口,当被观察者状态发生变化时接收通知。
UML 简单示意:
+-----------+ +------------+ | Subject |<>-------->| Observer | +-----------+ +------------+ | observers | | update() | | attach() | +------------+ | detach() | | notify() | +-----------+
在 Chromium 中,ObserverList
完全实现了这种一对多通知机制,并提供了线程安全版本 ObserverListThreadSafe
。
二、ObserverList 概述
ObserverList
是 Chromium base 提供的非线程安全版本的观察者列表,适用于单线程场景。
1. 头文件及基本类型
#include "base/observer_list.h"
常用类型:
base::ObserverList<MyObserver> observers;
-
MyObserver
必须是抽象类或接口类。 -
支持三种通知策略:
-
ObserverListPolicy::EXISTING_ONLY
:只通知已经存在的观察者。 -
ObserverListPolicy::NOTIFY_EXISTING_ONLY
:仅通知当前存在的观察者。 -
ObserverListPolicy::CHECK_EMPTY
:调试模式检查列表为空。
-
2. ObserverList API
class ObserverList<ObserverType, CheckedType = DEFAULT, AllowEmpty = false> { public: void AddObserver(ObserverType* observer); void RemoveObserver(ObserverType* observer); template <typename Functor> void Notify(Functor functor); // functor 为 observer 的回调函数 };
核心方法
-
AddObserver/RemoveObserver
- 添加或移除观察者,必须在同一线程操作。
-
Notify
-
遍历观察者列表,并调用回调函数。
-
内部处理了遍历期间删除 observer 的安全性 (使用
ObserverList::ForwardingInfo
)。
-
3. ObserverList 示例
#include "base/observer_list.h" #include <iostream> class MyObserver { public: virtual void OnEvent(int value) = 0; }; class ConcreteObserver : public MyObserver { public: void OnEvent(int value) override { std::cout << "Received event: " << value << std::endl; } }; int main() { base::ObserverList<MyObserver> observers; ConcreteObserver obs1, obs2; observers.AddObserver(&obs1); observers.AddObserver(&obs2); observers.Notify([](MyObserver* o){ o->OnEvent(42); }); observers.RemoveObserver(&obs1); observers.Notify([](MyObserver* o){ o->OnEvent(100); }); return 0; }
输出结果:
Received event: 42 Received event: 42 Received event: 100
解析
-
Notify
使用 lambda 遍历ObserverList
,安全处理了 observer 在通知过程中被删除的情况。 -
非线程安全,适用于 UI 或单线程逻辑。
4. ObserverList 内部机制
-
内部使用 双向链表 (
IntrusiveList
)维护 observer。 -
遍历时,使用 ForwardingInfo 记录当前遍历状态,保证删除当前 observer 不会破坏迭代。
-
CheckedObserverList 可在调试模式下检查空列表或重复添加。
三、ObserverListThreadSafe 概述
ObserverListThreadSafe
是线程安全版本,适用于多线程场景。
1. API
#include "base/observer_list_threadsafe.h" scoped_refptr<base::ObserverListThreadSafe<MyObserver>> observers;
-
内部使用 引用计数(RefCountedThreadSafe) 管理对象生命周期。
-
支持在任意线程添加/移除 observer。
-
通知回调可以指定在哪个线程执行(通过
base::SequencedTaskRunner
)。
2. ObserverListThreadSafe 示例
#include "base/observer_list_threadsafe.h" #include "base/task/sequenced_task_runner.h" #include "base/task/single_thread_task_runner.h" #include <iostream> class MyObserver { public: virtual void OnEvent(int value) = 0; }; class ConcreteObserver : public MyObserver { public: void OnEvent(int value) override { std::cout << "Thread-safe event: " << value << std::endl; } }; int main() { auto observers = base::MakeRefCounted<base::ObserverListThreadSafe<MyObserver>>(); auto obs = std::make_unique<ConcreteObserver>(); observers->AddObserver(obs.get()); // 在主线程通知 observers->Notify(FROM_HERE, [](MyObserver* o) { o->OnEvent(999); }); return 0; }
特点
-
Notify
必须传入FROM_HERE
(用于追踪调用栈)和 lambda。 -
支持跨线程安全调用。
-
内部使用锁或原子操作保证线程安全。
四、ObserverList 与 ObserverListThreadSafe 对比
特性 | ObserverList | ObserverListThreadSafe |
---|---|---|
线程安全 | ❌ 单线程 | ✅ 多线程 |
生命周期管理 | 需外部保证 observer 生命周期 | 内部 ref-count 管理,可延长生命周期 |
通知回调线程 | 当前线程 | 可指定线程 |
性能 | 高(无锁) | 相对低(锁或原子操作) |
使用场景 | UI 线程、单线程任务 | 多线程模块、后台任务 |
五、常见坑与注意事项
1. 遍历中删除 Observer
observers.Notify([&](MyObserver* o){ observers.RemoveObserver(o); // 安全,但注意遍历策略 });
-
ObserverList
内部已处理遍历中删除安全问题。 -
如果使用
EXISTING_ONLY
策略,可避免通知新加入的 observer。
2. Observer 生命周期管理
-
对于
ObserverList
,必须确保 observer 生命周期长于列表。 -
对于
ObserverListThreadSafe
,推荐使用scoped_refptr
或WeakPtr
避免悬空调用。
3. 跨线程通知延迟
-
ObserverListThreadSafe
的通知可能通过任务队列执行,回调不是立即执行。 -
需要注意调用线程与 observer 所在线程。
4. 重复添加与移除
observers.AddObserver(&obs1); observers.AddObserver(&obs1); // 重复添加无效
-
ObserverList
会检查重复添加。 -
ObserverListThreadSafe
内部同样有重复检查机制。
5. 性能考虑
-
ObserverListThreadSafe
内部加锁或原子操作,大量高频事件可能有性能开销。 -
对于 UI 更新等高频通知,优先使用单线程
ObserverList
。
六、ObserverList 使用场景分析
1. 单线程 UI 事件
-
浏览器标签页状态变化
-
界面组件刷新
-
Toolbar 按钮点击事件
2. 多线程后台任务
-
网络模块状态更新
-
下载任务状态变化
-
浏览器扩展事件通知
七、实战示例:结合 TaskRunner 异步通知
#include "base/observer_list_threadsafe.h" #include "base/threading/thread_task_runner_handle.h" #include <iostream> class MyObserver { public: virtual void OnDownloadComplete(int id) = 0; }; class DownloadObserver : public MyObserver { public: void OnDownloadComplete(int id) override { std::cout << "Download complete: " << id << std::endl; } }; int main() { auto observers = base::MakeRefCounted<base::ObserverListThreadSafe<MyObserver>>(); DownloadObserver obs; observers->AddObserver(&obs); // 异步任务 base::ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE, base::BindOnce([](scoped_refptr<base::ObserverListThreadSafe<MyObserver>> obs){ obs->Notify(FROM_HERE, [](MyObserver* o){ o->OnDownloadComplete(42); }); }, observers)); base::RunLoop().RunUntilIdle(); return 0; }
-
异步通知保证了 observer 在正确线程执行。
-
使用
scoped_refptr
管理 ObserverList 生命周期,避免线程结束前被释放。
八、总结
-
ObserverList
与ObserverListThreadSafe
是 Chromium base 库对 Observer 模式的高效实现。 -
ObserverList
适用于单线程场景,高性能但非线程安全。 -
ObserverListThreadSafe
适用于多线程场景,内部通过引用计数与锁保证安全。 -
使用时需注意:
-
observer 生命周期
-
遍历中删除 observer
-
跨线程异步通知
-
高频事件的性能开销
-
-
在浏览器开发中,它们被广泛用于 UI 更新、后台任务通知、模块解耦等场景。
九、参考源码阅读建议
-
base/observer_list.h
-
base/observer_list_threadsafe.h
-
Chromium TaskScheduler 与 TaskRunner 使用场景
-
WeakPtr
在 Observer 生命周期管理中的使用
本文全面介绍了 Chromium base 库中 Observer 模式实现,并结合示例、对比和常见坑进行讲解,帮助开发者在浏览器或多线程 C++ 项目中安全高效地使用观察者模式。