设计模式(一):总览——概念、原则,以及 AI 时代还需要“设计模式”吗
一、设计模式到底是什么
“设计模式”这个词被用得很滥。有人把它当成 23 个可以套用的代码模板,有人把它当成面试八股,也有人直接宣称它在现代语言和 AI 编程面前已经过时。这些理解都偏了。
GoF 的定义本身是克制的:设计模式是在特定情境下,对反复出现的设计问题的一种经过验证的解决方案描述。它描述的是一组协作的对象和它们之间的职责分配,而不一段可以复制粘贴的代码。
这个定义里有三个关键词经常被忽略:
“反复出现” 。只出现一次的问题,不需要模式。模式之所以成立,是因为同样的结构压力在一批系统中反复出现——行为需要可替换、创建逻辑需要收口、状态转换需要显式化——于是有人把应对这种压力的可靠方式总结成了模式。
“特定情境” 。模式不是无条件正确的。策略模式在“算法需要运行时切换”时成立,在“只有一个算法且短期不会增加”时就是负担。同一个结构,压力存在时是模式,压力不存在时就是过度设计。
“解决方案描述”,不是“代码模板” 。GoF 写的是意图、结构、参与者和后果,不是 Java 代码。这也是本系列坚持同时用 Java 和 Python 的原因:同一种意图,在两种语言中可以长得完全不同,模式真正稳定的是意图和结构关系,而不是类的形状。
一句话收束:设计模式是对“反复出现的设计压力”的命名和结构化回应。它的第一价值是让你认出压力,第二价值是提供一种已知可靠的回应方式。
二、模式从哪来,以及一个绕不开的批评
GoF 的 23 个模式诞生于 1990 年代中期的 C++ 和早期 Java 语境。那是一个语言表达力相对有限的环境:没有一等函数,没有装饰器语法,没有内置的事件机制,接口和继承是主要的抽象手段。许多模式正是为了弥补语言本身的表达不足而出现的。
这个批评是成立的,而且值得认真对待:在表达力更强的语言里,许多模式会“消失” 。单例在 Python 里常常只是一个模块级变量;策略在支持一等函数的语言里就是一个函数参数;观察者被事件循环和回调注册吸收;迭代器被生成器吸收。一篇广泛传播的批评文章说得更直接:“不是你的设计需要模式,是你的语言逼你用模式”。
但这个批评指向的是模式的类结构,不是模式所命名的设计压力。“算法需要可替换”这件事,在 Java 里需要策略接口,在 Python 里只需要传一个函数——表达方式变了,压力本身没有消失。
所以正确的结论不是“模式过时了”,而是:模式的形式会随语言和框架演进被吸收,但模式的意图和它所命名的压力,仍然是设计判断的内容。 识别压力、评估代价、在“加一层抽象”和“保持简单”之间做取舍,这件事不会因为语言变灵活而消失。
三、设计原则:模式下面的那层东西
如果只记模式而不理解原则,就会把模式用成“看症状开药”。模式是具体的处方,原则是诊断框架。最核心的是 SOLID 五条,加上几条同样重要的补充。
单一职责原则(SRP) :一个模块应该只有一个引起它变化的原因。这是所有原则的基础——如果一个类同时因为业务规则和持久化方式而变化,它就会在任何一个方向上的修改中被迫改动。许多模式的第一个动作,就是把混在一起的职责拆开。
开闭原则(OCP) :对扩展开放,对修改关闭。这是设计的终极目标,也是被误用最多的一条。策略、工厂、模板方法都在追求“加新行为时不改旧代码”,但每一次“对修改关闭”都是用一层抽象换来的。当变化方向不确定、或变化频率极低时,提前开闭反而制造了阅读成本。
里氏替换(LSP) :子类型必须能替换父类型而不破坏正确性。这条原则在实践中比听起来严格得多——它约束的不是语法,而是行为契约。一个“看起来能替换、实际会抛异常或改变语义”的子类,会让基于多态的所有模式(策略、状态、模板方法)全部失效。
接口隔离(ISP) :客户端不应该被强迫依赖它不用的方法。胖接口是适配器和装饰器最常见的成因——当一个接口把太多不相关的能力捆在一起,调用方要么被迫实现空方法,要么需要额外一层来“削窄”它。
依赖倒置(DIP) :高层模块不应该依赖低层细节,两者都应该依赖抽象。这条原则是过程式编程和面向对象设计的分水岭,也是几乎所有创建型模式和结构型模式的底层动机:工厂方法让创建依赖于抽象产品,依赖注入让业务逻辑依赖于接口而非具体实现。
在 SOLID 之外,还有两条对“该不该用模式”影响极大的原则:
组合优于继承。继承是白箱复用,父类的实现细节对子类可见,变化会沿着层级扩散;组合是黑箱复用,通过持有接口来委托。装饰器、策略、代理、桥接,本质上都是“用组合替代继承”的不同形态。
YAGNI(你不会需要它) 。这条原则和开闭原则构成一对张力。开闭原则说“为扩展留好口子”,YAGNI 说“等真的需要扩展时再说”。成熟的判断不是选边站,而是看变化是否已经发生或高度可预见:已经出现第二种算法,抽取策略是合理的;只是“将来可能有”,先写直接代码更诚实。
一句话记住原则和模式的关系:原则告诉你“什么样的设计在变化面前是脆弱的”,模式告诉你“针对某类脆弱,有一个经过验证的结构回应”。先诊断,再开方。
四、AI 时代,设计模式的角色变了,但没有退场
这是本文最想认真处理的部分。AI 编程助手已经能按一句提示生成“用策略模式重构这段代码”的完整实现,那设计模式还有学习的必要吗?
4.1 AI 降低了“写出来”的成本,但没有降低“判断该不该写”的成本
这是当前讨论中最被低估的一点。AI 生成模式结构的能力很强,但它不评估压力是否存在。一篇 2026 年的模式分析直接指出:AI 编码助手降低了模式的样板代码成本,这会让过度使用模式变得更可能,而不是更少——因为生成一个工厂层级和生成一个 if 分支的“手感成本”被拉平了。
换句话说,过去“写工厂方法太麻烦”这个摩擦,本身在某种程度上抑制了过度设计。AI 把这个摩擦消掉了,判断力就成了唯一剩下的防线。知道策略模式和状态模式在结构上几乎一样、但意图相反(策略由外部选择算法,状态由内部驱动转换),这种区分不会因为 AI 会写代码而变得不重要——恰恰相反,它是你审查 AI 产出时唯一有效的东西。
4.2 设计模式正在从“实现知识”变成“审查语言”
在 AI 辅助的开发流程中,人的核心动作正在从“写代码”转向“提要求、做判断、审结果”。在这个流程里,设计模式的实用价值集中在三个位置:
第一,它是向 AI 下达精确设计意图的词汇。 “用策略模式重构这段折扣计算,让新增会员等级时不需要修改现有类”比“把这段代码改得灵活一点”有效得多。模式名称压缩了一组设计约束,让提示词本身变得可审查。
第二,它是审查 AI 产出的判据。 AI 可以生成一个“看起来像观察者模式”的实现,但它可能没有处理观察者列表在通知过程中被修改的情况,也可能把异常吞掉。模式的结构描述提供了一个检查清单:参与者齐不齐、职责分配对不对、代价有没有被隐藏。研究也表明,LLM 对设计模式的理解存在系统性偏差,生成的代码可能“形似而神不似”。
第三,它是人和人之间的共同语言。 一篇批评文章在否定了模式的“菜谱”用法之后,仍然承认模式唯一站得住脚的价值是团队沟通的速记:你说“这里用了外观模式”,对方立刻知道你在子系统前面加了一个统一入口,不需要画图解释。这个价值在 AI 参与后反而上升了——当代码不完全由人逐行写出时,用模式名称来对齐“这里的设计意图是什么” ,比阅读生成出来的大量样板更高效。
4.3 一个更务实的框架:把模式放在“诊断—生成—审查”的链条里
与其争论“AI 时代还要不要学模式”,不如把它放进一条具体的工作流里看:
诊断阶段,人负责。 识别当前代码里是否存在“反复出现的设计压力”:条件分支在多个方法里重复、创建逻辑散落、状态转换靠布尔标志堆叠。这一步 AI 可以辅助扫描,但**“这个压力是否值得现在回应”** 是人的判断,因为它涉及对变化方向、团队能力和维护周期的理解。
生成阶段,AI 负责,人给约束。 用模式名称和意图描述来引导生成。研究表明,即使是简单的指令策略也能有效引导 LLM 产出符合特定模式的代码,而迭代式反馈效果更好。但生成的是结构,不是设计决策。
审查阶段,人负责,模式提供检查框架。 检查的不只是“代码能不能跑”,而是:参与者是否完整、职责是否错位、代价是否被接受。一个 AI 生成的策略模式如果引入了额外的间接层却没有带来可替换性收益,审查者应该有能力把它退回去。
这条链条的核心结论是:AI 把设计模式的“实现成本”降到了接近零,同时把“判断成本”的相对权重推到了最高。 过去你可以靠“写起来麻烦”来自然过滤掉不必要的模式;现在过滤必须靠理解。
4.4 所以,应该怎样学设计模式
如果目的仍然是“手写 23 个模式的代码”,那在 AI 时代确实性价比很低——需要时让 AI 生成即可。但如果目的是在 AI 产出的代码面前保持判断力,学习的重点应该转移:
从“记住实现”转向“理解意图和代价” 。单例的 DCL 怎么写可以查,但“这个场景到底该不该用单例、用了之后测试怎么办”是查不出来的。
从“背模式”转向“辨边界” 。策略和状态的结构几乎一样,工厂方法和抽象工厂的差别不在代码而在产品族的约束,装饰器和代理都持有同一个接口但目的完全不同。模式的边界,就是设计判断的边界。
从“在代码里找模式”转向“在压力里找模式” 。先看到重复的条件分支、散落的创建逻辑、到处传递的状态标志,再决定用哪个模式回应。模式是诊断之后的选项,不是扫描代码时的模板匹配。
五、本系列的读法
后面的每一篇会按统一结构展开:一个真实痛点 → 一句话本质与结构 → Java 实现(在这个语言中“正确”的写法) → Python 实现(最 Pythonic 的写法,通常不是逐行翻译) → 双语言对照表 → 现代视角(这个模式今天还值不值得手写) → 三十秒自测。
分类上沿用 GoF 的三分——创建型把“怎么造”从“要什么”中分离,结构型处理对象之间的组合关系,行为型处理职责分配和协作——但不按顺序硬啃 23 个。优先读日常高频的那一组:策略、工厂方法、装饰器、适配器、观察者、模板方法、单例。建立起“能认出压力”的语感之后,其余模式会容易得多。
第一篇文章的结论可以压缩成一句话:设计模式没有过时,但它的价值重心已经从“你会不会写”转移到了“你知不知道什么时候该写、什么时候不该写、以及如何判断别人写出来的东西对不对”。在 AI 能生成结构的时代,后一种能力是唯一不能被生成的部分。
- 点赞
- 收藏
- 关注作者
评论(0)