设计模式入门指南:从可维护代码理解 23 种经典模式

近期趋势:设计模式从“背概念”转向“解决维护问题”
在软件开发实践中,设计模式仍然是理解可维护代码的重要入口。近期更明显的趋势是,团队不再把设计模式当作固定模板去套用,而是更关注它能否降低修改成本、隔离变化、提升协作效率。

随着业务系统持续迭代,代码往往会经历需求变更、模块拆分、接口扩展、性能优化等过程。设计模式的价值,通常不在于让代码看起来复杂,而在于帮助开发者在变化发生时少改代码、少引入副作用。
对于初学者而言,学习 23 种经典设计模式的重点,不是一次性记住所有类图,而是理解每种模式试图解决哪类问题,以及它适合出现在什么上下文中。
行业背景:为什么经典 23 种模式仍被反复讨论
经典 23 种设计模式通常按创建型、结构型、行为型三类划分。这种分类方式有助于开发者从“对象如何创建”“对象如何组合”“对象如何协作”三个角度理解代码结构。

在面向对象开发中,需求变化经常体现在对象职责变化、依赖关系变化、调用流程变化上。设计模式正是围绕这些常见变化提供可复用的设计经验。
需要注意的是,设计模式并不是某种语言的专属语法,也不是架构层面的万能方案。不同语言、框架和团队规范会影响模式的表达方式。例如,在某些语言中需要手写的模式,在另一些语言或框架中可能已经被语法特性、依赖注入容器或标准库弱化。
用户关注点:初学者应先理解哪些核心问题
很多开发者学习设计模式时,会遇到一个共同问题:能看懂定义,却不知道什么时候使用。更有效的学习方式,是先从代码痛点出发。
- 当对象创建逻辑复杂,且调用方不应关心细节时,可以关注创建型模式。
- 当多个类之间组合关系复杂,或者需要兼容旧接口时,可以关注结构型模式。
- 当对象之间调用流程频繁变化,或者需要解耦发送者与接收者时,可以关注行为型模式。
- 当代码已经足够简单时,不必为了使用模式而主动增加抽象层。
判断一个模式是否值得引入,可以看它是否明确减少了重复、降低了耦合、稳定了扩展点。如果只是增加类数量,却没有改善变化成本,就可能属于过度设计。
创建型模式:关注对象如何被创建
创建型模式主要解决对象实例化过程中的复杂性问题。它们常用于隐藏创建细节、统一构建流程、延迟对象生成,或者控制对象数量。
| 模式 | 核心理解 | 常见适用场景 |
|---|---|---|
| 单例模式 | 保证某类在特定范围内只有一个实例,并提供统一访问点。 | 配置管理、资源管理等需要共享状态的场景,但应谨慎处理并发和测试问题。 |
| 工厂方法模式 | 把对象创建延迟到子类或具体工厂中完成。 | 调用方只依赖抽象类型,具体产品类型可能变化。 |
| 抽象工厂模式 | 创建一组相关对象,保证它们属于同一产品族。 | 多套风格、环境或平台适配,需要成组切换对象实现。 |
| 建造者模式 | 把复杂对象的构建过程拆分为多个步骤。 | 对象参数较多、构造过程有顺序或组合约束。 |
| 原型模式 | 通过复制已有对象创建新对象。 | 对象创建成本较高,或需要基于已有配置快速生成相似对象。 |
学习创建型模式时,应重点观察“谁负责创建对象”。如果调用方到处使用复杂构造逻辑,后续替换实现会变得困难,创建型模式就可能有价值。
结构型模式:关注对象如何组合
结构型模式用于处理类与对象之间的组合关系。它们通常帮助系统在不大幅修改原有代码的情况下扩展能力、适配接口或组织层次结构。
| 模式 | 核心理解 | 常见适用场景 |
|---|---|---|
| 适配器模式 | 把一个不兼容的接口转换成调用方期望的接口。 | 接入旧系统、第三方接口或历史代码。 |
| 桥接模式 | 把抽象部分与实现部分分离,使二者可以独立变化。 | 多个维度同时变化,避免类数量快速膨胀。 |
| 组合模式 | 把单个对象和对象集合统一看待。 | 树形结构、菜单、目录、组织层级等场景。 |
| 装饰器模式 | 在不修改原对象的情况下动态增加功能。 | 功能可叠加、组合顺序可能变化的场景。 |
| 外观模式 | 为复杂子系统提供一个简化入口。 | 封装内部复杂流程,降低调用方使用成本。 |
| 享元模式 | 共享大量细粒度对象中的相同部分。 | 对象数量庞大且存在可复用内部状态时。 |
| 代理模式 | 通过代理对象控制对真实对象的访问。 | 权限控制、延迟加载、远程调用、缓存等场景。 |
结构型模式常见的判断依据是:系统是否因为对象组合方式不清晰而难以扩展。如果只是为了包装而包装,反而会让调用链变长、排查成本上升。
行为型模式:关注对象如何协作
行为型模式主要处理对象之间的职责分配和通信方式。它们适用于流程分支复杂、状态变化明显、请求传递链较长的代码。
| 模式 | 核心理解 | 常见适用场景 |
|---|---|---|
| 责任链模式 | 让请求沿处理链传递,直到被某个处理者处理。 | 审批、过滤、校验、拦截等分步骤处理。 |
| 命令模式 | 把请求封装成对象,使调用、排队、撤销等操作更灵活。 | 任务队列、操作记录、撤销重做等场景。 |
| 解释器模式 | 为特定语法或规则定义解释逻辑。 | 简单规则引擎、表达式解析,但复杂场景通常需要更系统的解析方案。 |
| 迭代器模式 | 在不暴露集合内部结构的情况下遍历元素。 | 集合访问、统一遍历接口。 |
| 中介者模式 | 用中介对象集中协调多个对象之间的交互。 | 对象关系网复杂、相互引用过多的场景。 |
| 备忘录模式 | 在不破坏封装的前提下保存对象状态,便于恢复。 | 草稿、撤销、快照等需要状态回退的场景。 |
| 观察者模式 | 当一个对象状态变化时,通知依赖它的其他对象。 | 事件通知、订阅发布、界面刷新等场景。 |
| 状态模式 | 把不同状态下的行为封装到独立状态对象中。 | 订单流转、任务生命周期、设备状态等场景。 |
| 策略模式 | 把可替换的算法或规则封装起来,在运行时选择。 | 计费规则、排序规则、校验规则等可切换逻辑。 |
| 模板方法模式 | 在父类中定义流程骨架,把部分步骤交给子类实现。 | 流程稳定、细节可变的处理过程。 |
| 访问者模式 | 把作用于对象结构的操作从对象本身分离出来。 | 对象结构相对稳定,但需要频繁新增操作的场景。 |
行为型模式的共同目标,是减少对象之间的硬编码依赖。它们可以让流程更清晰,但如果业务规则本身简单,直接代码往往更容易理解。
可能影响:对代码质量和团队协作的实际意义
合理使用设计模式,可能带来几方面影响。首先是可读性提升,团队成员可以通过模式名称快速理解设计意图。其次是修改范围收敛,变化点被隔离后,新增功能不一定需要大面积改动旧代码。
在多人协作中,设计模式也能减少沟通成本。例如提到“策略模式”,通常意味着某段规则可以替换;提到“观察者模式”,通常意味着存在事件通知关系。这种共同语言有助于代码评审和方案讨论。
但设计模式也有成本。抽象层增加后,代码跳转路径会变长;类数量增加后,初学者理解成本会上升;如果模式使用不当,还可能让简单问题复杂化。
设计模式的正确使用标准,不是“代码里出现了多少模式”,而是“变化发生时,代码是否更容易被安全修改”。
后续观察:学习设计模式应关注哪些方向
后续学习设计模式,可以从实际项目中的重构机会入手,而不是孤立记忆定义。一个有效方法是先识别代码坏味道,再判断是否有合适模式可用。
- 如果大量条件分支根据类型选择不同算法,可以观察是否适合策略模式或状态模式。
- 如果创建对象的代码分散在多个地方,可以观察是否适合工厂方法、抽象工厂或建造者模式。
- 如果一个类承担太多协调职责,可以观察是否需要中介者、外观或责任链等方式拆分。
- 如果系统经常需要通知多个模块,可以观察是否适合观察者模式或事件机制。
- 如果多个功能需要灵活叠加,可以观察装饰器模式是否比继承更合适。
同时,也要结合语言特性和框架能力判断是否需要手写模式。现代开发环境中,依赖注入、函数式接口、注解机制、事件总线、组件化框架等,都可能改变设计模式的落地方式。
入门建议:从三个原则理解 23 种模式
对于初学者,可以用三个问题贯穿 23 种模式的学习。
- 变化点在哪里:是对象创建会变,组合关系会变,还是业务行为会变。
- 依赖是否稳定:调用方是否依赖了过多具体实现,导致替换成本较高。
- 抽象是否值得:新增的接口、类和层次是否真正降低了未来修改成本。
如果一个模式能清楚回答这些问题,它通常更容易在项目中发挥作用。反之,如果只是为了符合某个概念而引入模式,代码可能会变得更难维护。
总体来看,设计模式入门不应停留在术语层面。理解 23 种经典模式,更重要的是建立一种面向变化的代码思维:在保持当前实现清晰的同时,为合理的扩展留下空间。