前言
这本书怎么组织
Section titled “这本书怎么组织”本书参考了 Gamma、Helm、Johnson 和 Vlissides 的《Design Patterns: Elements of Reusable Object-Oriented Software》(1994)、Freeman 和 Robson 的《Head First Design Patterns》(第 2 版,2020)、Refactoring.Guru 的《Dive Into Design Patterns》,以及 Python 和 TypeScript 的官方文档;书中案例均为自行设计。全书分六个部分,另有一个附录。第一部分只有第 1 章,讲设计模式(Design Pattern)是什么、不是什么,贯穿全书的几条设计原则,以及 23 个模式的总表:中文名、英文名、一句话功能、典型场合和流行程度。
第二、三、四部分是正文主体,按 GoF 的分类依次介绍创建型(Creational)、结构型(Structural)和行为型(Behavioral)模式,每个模式一章。每个部分开头有一章导读,讲这一类模式共同解决什么问题,列出本部分的模式一览,并告诉你“遇到什么问题先看哪个”。
第五部分是第 28 到 30 章。第 28 章讲怎么选模式,从问题出发反查;第 29 章讲现代语言里的模式,看一等函数、生成器、模块这些语言特性替你省掉了哪些类;第 30 章带你走出 GoF,认识依赖注入、仓储、中间件管道这些常见的其他模式。第六部分是可用资源,按方向列出想继续深入时值得读的书、文档和开源项目。最后的附录 A 是速查表与易混对比,方便你日后快速翻查。
每一章的固定节奏
Section titled “每一章的固定节奏”每个模式章节的开头是两行题记:一句话说这个模式干什么,一句话说它解决什么痛。之后用同一套 11 个小节,编号为 N.1 到 N.11(N 是章号),顺序不变:
- N.1 一个场景:来自日常开发的简单案例。
- N.2 先按直觉写:传统写法,Python 和 TS 各一版。
- N.3 需求变了:加一条新需求,具体数出要改几处、哪里会复制粘贴、哪里会漏改。
- N.4 用该模式重写:模式版本,并逐点说明上一节的问题怎么被消除。
- N.5 模式定义:正式定义、结构图、参与者和常见场景。
- N.6 更简洁的写法:可选小节,只在语言特性能明显简化模式时出现,一共 8 个模式有,没有这一节的章节后面的编号顺延。
- N.7 真实系统里的例子:两个知名系统的简化可运行版本。
- N.8 什么时候别用:滥用的具体代价。
- N.9 容易混淆的模式:与相近模式的区别,一张小表。
- N.10 练一练:一道小题,答案不在正文里。
- N.11 小结:3 到 5 条要点。
“先看问题再看定义”是刻意的安排。定义本身很短,难的是知道它为什么存在。所以你可以只读 N.1 到 N.4:看到旧写法在新需求面前怎么吃力,再看模式怎么化解。后面的内容等需要时再回头读:定义、结构图和参与者表帮你把案例里的经验归纳成可复用的知识,真实系统的例子让你看到同一个模式在知名项目里长什么样,易混模式表和练习则用来检验自己是否真的分清了。
不论哪种读法,建议每读完一章就停下来,合上书,试着不看答案完成章末的练习。设计模式不是背出来的,而是在一次次把旧写法改成新写法的过程中,逐渐形成手感的。
有三种读法。第一种从头读,适合第一次系统学习,顺序是按“最易懂、最常用”排的。第二种按第 1 章的总表挑流行度高的模式读,先拿下策略、观察者、装饰器、工厂方法这些日常最常碰到的。第三种带着问题读:手头代码正在变得难改,就从第 28 章的决策表反查该看哪一章。
运行代码前的准备
Section titled “运行代码前的准备”本书的完整示例都能跑,只需要两样东西:
- Python 3.12 以上,用
python --version核对。 - Node 22 以上,并全局装 tsx(
npm install -g tsx)。
每个示例都是单文件,不依赖第三方库:python xxx.py 或 tsx xxx.ts 直接运行。预期输出写在文件末尾的注释里,跑完对照即可。如果输出和注释不一致,先检查版本是否满足上面的要求,再检查是否完整复制了整个文件。带 # 输出:(TS 是 // 输出:)注释的代码块都是完整的文件,复制下来就能运行,不另提供下载;正文里只有几行、没有输出注释的是片段,用来指出改动的位置。建议你不要只看不跑:把案例里的需求变更自己动手加一遍,感受会比读文字深得多。
- 术语第一次出现时给出英文原名,之后用中文名。
- 同一个案例总是 Python 在前、TS 在后。Python 版通常更短,先看短的,再看结构更完整的 TS 版。两个版本的结构、命名和输出保持一致,所以你只熟悉其中一种语言也能读懂,另一种当作对照即可。
- 代码文件末尾
# 输出:下面的注释,是整个文件运行后应该打印的结果(TS 里写作// 输出:)。 - 类图的画法:实线空心箭头表示继承,虚线空心箭头表示实现接口,带菱形的线表示组合,虚线箭头表示依赖。
- 时序图的读法:竖线是对象的生命线,横向箭头是一次调用,从上到下是时间的先后。