Chromium 如何实现控制反转

2025-03-04 pv

控制反转(Inversion of control)是一种设计模式(Design pattern)。

按照维基百科的解释,

依赖反转原则是指一种特定的解耦形式,使得高层次的模块不依赖于低层次的模块的实现细节,依赖关系被颠倒(反转),从而使得低层次模块依赖于高层次模块的需求抽象。

有点抽象。

举个例子。

你去餐厅吃饭,你要求厨师给你做一个汉堡,厨师做好后怎么取餐,取决于厨师的操作,服务员给你端上来,或者自己去吧台取。

你不需要关心厨师怎么处理这件事。只需要知道,汉堡做好,你会通过某种方式得到它。

此时,控制发生了反转。

Chromium 是一个复杂的工程项目,代码行数超过 3200 万🔗,除了 base 库,更是有着大量第三方库。如果没有适度的抽象和解耦,如此庞大的代码仓库将会迅速腐烂,变得难以维护。

控制反转,便是 Chromium 采取的一种应对之道。

1. 概念

控制反转有两个核心原则:

  1. 高层模块不应依赖低层模块的实现
  2. 抽象不应依赖细节

这两个原则,说的其实是一件事:解耦

这是面向对象编程里经常提及的概念。

耦合过重的组件,通常难以维护,而且不便于扩展。

如果一项改动,牵一发而动全身,那么基本上没有人敢轻举妄动。更谈不上敏捷开发了。

好的解耦应该保证,若有改动,影响范围够小。

这需要清晰的模块划分,明确的接口定义,以及松散耦合的组件交互。

2. Chromium 的设计

Chromium 主要用到了三种手段:

  • Callback (回调)
  • Observer (观察者)
  • Delegate (委托)

举个生活化的例子。

老王喜欢喝茶。

喝茶就要先烧水,可惜老王家的热水壶比较老式,得不停地去看是否烧好。

老王有点不耐烦,心想:我怎么能依赖热水壶的特性呢?

于是发明了一个工具:开水报警器。

等水烧开,开水便会触发报警器,通知老王接热水。

老王很满意。

开水报警便是一个 Callback。

老李也喜欢喝茶。

可惜,老王的开水报警器只能通知老王一个人。

如果每个人都放一个开水报警器在热水壶里,热水壶很快就满了。

老王灵机一动,想到一条商机。

在开水报警器旁增加一个二维码,想知道水是否烧开的,扫码注册,水烧开后会通知。

老王、老李都很满意,他们都是 Observer。

有天,老王的热水壶坏掉了,想换一个,发现很不方便:热水壶和开水报警器是绑定在一起的,要换就得一起换。

老王心想,他需要的只是开水,是不是热水壶烧的并不重要,如果有开水公司,也是可以的。

那些能提供开水功能的,在老王这里都是 Delegate。

简单地说,Callback 和 Observer 是等着被动通知,而 Delegate 是主动提供

3. 启发

对于一个简单系统,解耦与否并没有那么重要。即便耦合重,重构的负担也不大。

对于复杂系统则不然。

在开发中,顶层设计很重要。一定是先接口(Interface),后实现(Implementation),接口通常稳定,而实现易变。

先想清楚去哪里,再决定怎么去

这是我老板经常对我讲的。

现在各种代码生成的工具层出不穷,GitHub Copilot、Cursor,还有 Trae,实现一个想法变得异常简单。

能提出创意的想法,清楚地表达,越来越重要

不仅在软件开发领域如此。

作为一名程序员,你的技能,经验,阅历,越通用越好,如果和公司、行业存在较深耦合,就要警惕了。未来某天,行业发展进入下行周期,泥沙俱下,没有一点影响,很难。

之前 文章🔗 文章提到的三点,回过头看,何其然也:

  • 可迁移技能
  • 有意义的经验
  • 持久的关系

4. 总结

控制反转是一种手段,解决的是耦合问题。

本质是为了降低复杂度

这是软件工程面临的终极问题。毕竟整个宇宙,就是有着熵增的惯性。

人也如此。

年少天真童趣,进入社会,愈发老成,心思越来越深,想法越来越多,胃口越来越大。

目前我能想到的,就是剪枝,放低姿态,减少低质信息摄入,专注某个细分领域。后面有时间展开讲。

(完)

参考

  1. 依赖反转原则 - 维基百科,自由的百科全书🔗
  2. Chromium Docs - docs/patterns/inversion-of-control.md🔗
在 GitHub 上编辑本页面

最后更新于: 2025-03-06T05:01:28+08:00