写在前面 · 模式是给痛点立的牌子
用白话把 GoF 23 种设计模式讲清楚。
先说一句可能得罪人的大实话:大部分人是先会背 23 个模式的名字,再慢慢忘光,最后在某次重构里自己重新发明了其中几个——然后才真正懂了它们。
这个系列想把顺序倒过来:先让你看见痛,再告诉你前人是怎么止痛的。
设计模式到底是个啥
把话说白了:设计模式就是前人在某个坑里摔多了,爬出来之后在坑边立的一块牌子,上面写着“这么走能绕过去”。
它不是语法,不是框架,不是你 import 进来就能用的库。它是一种在特定场景下反复被验证有效的对象组织套路。1994 年,四位作者(业内昵称 GoF,Gang of Four,“四人帮”)把当时面向对象界反复出现的 23 种套路收集成册,写了本《Design Patterns》,从此这 23 个就成了程序员的“普通话”——你说“这里用个观察者”,对面立刻懂,不用画半小时图。
所以模式最大的价值有两层:一层是解决方案本身(怎么写),另一层是词汇表(怎么沟通)。后者常被低估——团队里能用一个词对齐一整套设计,是极高效的事。
为什么会有这些痛点:一切都因为“变”
如果需求永远不变,世界上就不需要设计模式——一把梭把功能写完,能跑就行。
问题是需求一定会变。今天只支持支付宝,明天加微信,后天老板要加数字货币;今天导出 PDF,下周要导出 Excel。几乎所有设计模式,本质上都在回答同一个问题:当某个东西要变的时候,怎么让改动的影响范围最小?
GoF 有一句纲领性的话,值得刻在脑子里:
Encapsulate the concept that varies.(把“会变的那部分”封装隔离起来。)
你会发现,23 个模式几乎都是这句话在不同场景下的变体:策略模式隔离“会变的算法”,观察者模式隔离“会变的通知对象”,工厂模式隔离“会变的具体类”……看模式时别只盯着类图,要问一句:它到底在隔离什么变化? 抓住这条线,23 个模式就不再是 23 条孤立的口诀,而是一张网。
三大类,一句话分清
GoF 把 23 个模式按“管什么”分成三类,这个分法非常好记:
| 类别 | 管什么 | 一句话 | 典型代表 |
|---|---|---|---|
| 创建型 | 对象怎么生 | 把 new 这件事管起来,别到处乱 new | 单例、工厂、建造者 |
| 结构型 | 对象怎么拼 | 把小对象组装成大结构,还不别扭 | 适配器、装饰器、代理 |
| 行为型 | 对象怎么处 | 对象之间怎么分工、怎么通信 | 策略、观察者、命令 |
创建型管“生”,结构型管“拼”,行为型管“处对象关系”——生、拼、处,三个字记一辈子。
每篇怎么讲
为了不写成第 101 本“设计模式速查手册”,本系列每个模式都按同一条线索展开,力求把“背名词”变成“懂痛点”:
- 这是什么 —— 先用一个现实生活里的例子把直觉建立起来(遥控器、咖啡加料、公司审批流……),再回到代码。
- 解决什么痛 —— 不先讲解法,先把“不用这个模式会有多难受”演示给你看。痛点不清,解法无感。
- 怎么实现 —— 给出 Go 的惯用实现(必要时对比 C++ / Java),不堆代码,只讲关键结构。
- 有哪些坑 —— 模式用错比不用还糟。这一节专讲过度设计、误用、以及“看起来像其实不是”的陷阱。
- 开源里怎么用 —— 到真实的知名项目(Go 标准库、Kubernetes、Java JDK、Nginx……)里,把这个模式活生生指给你看。
一句提醒贯穿全系列:模式是解药,不是维生素。没病别乱吃。见到痛点才用对应的模式,是工程师;为了用模式而制造痛点,是“模式病”。本系列每一篇的“坑”小节,有一半篇幅在劝你别乱用。
关于代码
- 主语言 Go:用 Go 的惯用法(小接口、组合、函数值、
error返回)来写,你会发现不少“经典 OOP 模式”在 Go 里轻得几乎看不见——这本身就很说明问题。 - 辅以 C++ / Java:在能体现差异的地方,顺手对比一下 C++ 和 Java 的写法,看看同一个痛点在不同类型系统下怎么止。
- 完整可运行代码都在配套开源仓库,9 种语言对照实现,建议边读边跑: 👉 github.com/davidapp/GoF
准备好了就从单例模式开始——它最简单,却也是争议最大、被骂最多的一个,适合用来热身。