{"name":"设计模式","id":"软件工程-设计模式-设计模式","content":"# 设计模式\n\n## 概述\n\n软件系统面临一个根本性困境：**需求永远在变，但系统必须保持可控**。\n\n人类应对这一困境的手段，经历了三个认知层次的演进：\n\n- **分解**：将大问题拆解为小问题，降低局部复杂度\n- **抽象**：隐藏实现细节，暴露稳定接口\n- **模式**：识别重复出现的问题结构，建立可传播的应对共识\n\n设计模式处于第三个层次。它不是代码模板，也不是类图范式，而是一种**对工程经验的知识编码机制**：将分散在无数工程师头脑中的隐性设计智慧，转化为可命名、可传播、可复用的显性知识。\n\n从更高的维度看，设计模式是人类**模式识别能力**在软件工程领域的产物——在混沌的需求变化中识别秩序，在不断演进的系统中寻找稳定结构，并将这种识别的结果编码为可供团队共享的认知单元。\n\n## 本质\n\n软件复杂性有两个来源：\n\n- **规模复杂性**：系统变大带来的耦合与理解成本\n- **变化复杂性**：需求演进带来的不确定性与脆弱性\n\n设计模式针对的是后者。它的底层逻辑是**封装变化**：识别系统中的\"稳定点\"与\"变化点\"，将变化隔离在有限边界内，让不变的部分承载系统的结构骨架。\n\n这揭示了设计模式存在的根本原因：\n\n> **变化是软件系统的宿命，设计模式是人类驯服这种宿命的方式。**\n\n从认知层面看，设计模式是将 **上下文 - 问题 - 解决方案** 三元结构转化为可传播认知单元的机制。它来自实践归纳，而非理论演绎：先有反复出现的问题，才有模式；先有模式被多次验证，才有命名与传播。\n\n这是它区别于其他工具的根本所在：\n\n| 工具 | 解决的问题 |\n|------|-----------|\n| 算法 | 计算问题 |\n| 框架 | 执行骨架 |\n| 最佳实践 | 具体建议 |\n| **设计模式** | **识别问题结构的认知框架** |\n\n因此，设计模式的力量不在于提供现成答案，而在于帮助工程师识别\"当前问题属于哪类已知结构\"，从而激活对应的应对策略。它是介于**设计原则（Why）**与**系统架构（What）**之间的中观层抽象，是将原则具象化、将架构模块化的桥梁。\n\n## 模式的结构化表达模型\n\n设计模式要成为可传播的知识，必须具备标准化的表达形式。这个模型的核心价值不是提供填空模板，而是**将隐性的设计智慧转化为显性的、可评审的结构化知识**。\n\n一个成熟的设计模式包含以下六个核心元素：\n\n| 元素 | 作用 |\n|------|------|\n| **名称（Name）** | 沟通的锚点，是模式存在的前提 |\n| **动机（Motivation）** | 通过具体场景说明\"为什么这个问题需要这个解法\"，是模式可理解性的核心 |\n| **意图（Intent）** | 解决什么核心问题，以及期望达到的设计效果 |\n| **结构（Structure）** | 角色、职责、协作方式，可用类图或关系描述 |\n| **适用性（Applicability）** | 在哪些上下文中适用，在哪些情况下不适用 |\n| **后果（Consequences）** | 使用该模式带来的收益、限制与代价 |\n\n其中，**动机**是最容易被忽略、也最不能缺少的元素：没有动机，模式就成了没有来历的答案，读者无法判断自己的问题是否真的属于这个模式的适用范围。\n\n## 设计模式的关键属性\n\n设计模式不是单纯的\"解决方案\"，而是一类具有明确品质标准的工程经验。这些属性之间存在内在的逻辑层次，而非相互独立：\n\n```\n可命名性（前提）→ 可复述性（手段）→ 可沟通性（目的）\n                                    ↓\n                          可复用性（效果）→ 可演化性（生命力）\n```\n\n### 可命名性\n\n必须能用一个简洁的名称表达核心意图。命名不是标签，而是认知压缩：一个好的名称能让听者在没有看到任何代码的情况下，就对结构意图有基本判断。**命名是模式得以存在和传播的前提。**\n\n### 可复述性\n\n模式的结构与意图能够被清晰传递，让接收方理解并掌握其应用方式。可复述性是沟通层面的能力——不能被复述的模式无法在团队中扩散，只能停留在发现者的头脑里。\n\n### 可沟通性\n\n设计模式本质上是一种团队共享语言。一句\"用策略模式\"即可传递：有可替换行为、有统一接口、有运行时切换的完整结构信息，极大压缩了沟通成本。\n\n### 可复用性\n\n模式的结构在逻辑层面可重用，甚至可以跨语言、跨框架迁移。这种复用是**结构的复用**，而非代码的复制。\n\n### 可演化性\n\n优秀模式可随着技术变化而演化，不是固定不变的代码模板。例如，随着函数式编程的兴起，策略模式在很多语言中直接退化为高阶函数——模式的意图保留了，形式演化了。\n\n### 上下文依赖性\n\n**这是设计模式区别于算法最关键的属性**：模式只在特定上下文中有意义。脱离了上下文，模式就从\"应对变化的工具\"退化为\"为模式而模式\"的教条。判断一个模式是否适用，本质上是在判断当前问题的上下文是否与模式的适用条件匹配。\n\n## 模式的边界与误区\n\n判断是否应该引入设计模式，有一个根本原则：**只有当变化来源明确、且该变化在未来会真实发生时，引入模式才有意义。** 脱离这个前提，模式带来的只是复杂度，而不是弹性。\n\n### 模式的边界\n\n**首要边界：无变化来源，不引入模式。**\n如果一个模块的需求极度稳定、职责单一、没有可预见的扩展点，强行引入模式只会增加无谓的抽象层。模式是为变化服务的，没有变化就没有使用模式的理由。\n\n其余边界：\n\n* 不是微观代码技巧（那是 idiom，如迭代器写法、空对象处理）\n* 不是框架级架构（那是 architecture，模式是构成架构的基础粒度）\n* 不适用于需求极度稳定的领域（如底层硬件驱动、科学计算内核）\n* 不直接带来性能收益，主要提升的是结构弹性与可维护性\n\n### 常见误区\n\n**误区一：将\"记住结构\"等同于\"掌握能力\"**\n\n很多工程师能背出 GoF 23 种模式的类图，但在实际工程中依然无法判断当前问题是否适合某个模式。模式的核心能力是**识别问题结构**，而不是记住解法结构。两者方向相反：前者是从问题出发找模式，后者是从模式出发找问题。\n\n**误区二：忽略上下文，直接套用模式名**\n\n看到\"需要切换行为\"就用策略模式，但没有验证是否真的有多个可替换的行为实现同时存在。这个误区的本质是：**把模式当成了触发词，而不是上下文匹配的结果**。模式名是沟通语言，不是判断依据。\n\n**误区三：在没有变化来源的地方引入结构复杂度**\n\n为了\"扩展性\"和\"灵活性\"而过度抽象，给每个类加接口、每个行为加工厂。这类问题的根源是混淆了\"可能的变化\"与\"真实的变化\"——设计模式应该应对已知的、可预见的变化来源，而非假想的未来需求。\n\n**误区四：将模式理解成类图模板**\n\n只复制模式的结构形式，忽略其意图与上下文约束。结果是代码看起来像某个模式，但解决的不是那个模式针对的问题——形似而神不似，反而制造了理解障碍。\n\n## 模式与设计原则、架构的关系模型\n\n三者处于不同的抽象粒度，构成一个从思想到结构的完整认知层次：\n\n```\n设计原则（思想层）→ 设计模式（结构层）→ 系统架构（系统层）→ 具体实现（代码层）\n```\n\n### 设计原则 → 设计模式：原则驱动模式产生\n\n设计原则是抽象的思想指导，设计模式是原则落地为可复用结构的具体形式。原则回答\"为什么要这样设计\"，模式回答\"用什么结构来体现这个原则\"。\n\n这种驱动关系是可追溯的：\n\n| 设计原则 | 驱动出的模式 | 驱动逻辑 |\n|---------|------------|---------|\n| 开闭原则（OCP）| 策略模式、装饰器模式 | 对扩展开放意味着行为变化点必须被封装 |\n| 依赖倒置（DIP）| 工厂方法、抽象工厂 | 依赖抽象而非具体，推动出创建与使用的解耦 |\n| 单一职责（SRP）| 命令模式、外观模式 | 职责分离要求将可变行为从稳定结构中剥离 |\n\n### 设计模式 → 系统架构：模式是架构的局部承载\n\n架构不是模式的简单组合——架构还包含技术选型、质量属性权衡（性能、可用性、安全）、部署决策等内容，这些远超模式的范畴。\n\n更准确的关系是：**模式承载了架构的部分局部结构，是架构决策得以落地的基础粒度。**\n\n这种关系是双向的：\n\n- **自下而上**：多个模式的组合形成架构的局部结构（如事件驱动架构大量使用观察者模式）\n- **自上而下**：架构决策约束了哪些模式在当前系统中是合适的（如微服务架构限制了依赖跨服务共享状态的模式）\n\n> 模式不是架构，但架构的结构性决策离不开模式；架构不由模式决定，但模式塑造了架构的局部形态。\n\n## 模式的生命周期\n\n设计模式不是学习来的，而是从实践中抽象出来的；也不是静态资产，而是会随技术演进而演化乃至消亡。理解模式的完整生命周期，既有助于团队主动沉淀新模式，也有助于判断现有模式是否仍然适用。\n\n### 涌现：识别重复结构\n\n模式始于观察。当多个项目出现相同痛点、多个模块在应对同类变化来源时，重复的结构开始浮现。\n\n这一阶段的核心动作是**识别**，而非设计：不是主动去\"设计一个模式\"，而是发现\"这个问题我们以前解决过，结构是相似的\"。\n\n### 抽象：提炼角色与协作\n\n识别到重复之后，需要从具体实现中剥离出通用结构：\n\n- 抽象参与角色，明确各自职责\n- 找到系统中的**稳定点**（不随需求变化）与**变化点**（需要被封装的部分）\n- 建立角色之间的协作关系\n\n### 命名：形成可沟通语言\n\n抽象完成后，命名是将模式从个人认知转化为团队共识的关键一步。名称应准确、简洁、具有认知统一性——一个好的名称本身就能传递结构意图。\n\n### 验证：跨项目稳定化\n\n将提炼出的结构在其他项目或场景中尝试应用，通过团队评审优化边界与适用性。只有经过多次独立验证的结构，才能算作真正的模式，而非一次性的局部解法。\n\n### 泛化与成熟：成为团队共识\n\n验证稳定后，模式进入推广阶段：按照标准化的表达模型（名称、动机、意图、结构、适用性、后果）归档到模式库，形成团队可共享的知识资产，并逐步成为设计评审和日常沟通中的通用语言。\n\n### 弃用：随技术变迁被取代\n\n模式不是永久有效的。当底层技术范式发生变化，某些模式会弱化甚至消亡。例如随着函数式编程的兴起，策略模式在很多语言中直接退化为高阶函数；随着协程和响应式流的普及，一些传统线程同步模式也逐渐被替代。\n\n弃用不是失败，而是模式生命力的自然终点——**模式的意图可能永远有效，但实现它的结构形式会随技术演进而改变。**\n\n## 反模式\n\n反模式是**在特定上下文中反复出现、看似合理但实际上弊大于利的做法**。它与普通的坏代码有本质区别：\n- 它是**重复出现的结构**，不是偶发失误\n- 它有**看起来合理的动机**——正因如此，它才会被反复采用\n\n反模式之所以危险，恰恰在于它的\"合理外表\"：工程师是出于好意才引入它的。\n\n### 识别方法\n\n识别反模式不是观察结果，而是在做设计决策时主动追问：\n\n- 引入这个结构的动机是什么？是应对**真实存在的变化来源**，还是为假想的未来需求付代价？\n- 使用这个结构后，代码是否变得更难理解、更难修改？\n- 如果把这个抽象层去掉，系统会变得更简单吗？\n\n### 典型反模式\n\n**过度工程（Over-Engineering）**\n\n在没有真实变化来源的地方引入策略、工厂、装饰器等模式。动机是\"以后可能需要扩展\"，但结果是为假想需求付出了真实的复杂度代价。判断依据：**扩展点从未被用到过。**\n\n**神类（God Class）**\n\n一个类随系统演进不断膨胀，承担了本应分散到多个角色的职责。它\"能用\"，所以没有人敢动，但修改任何一处都可能牵连意想不到的地方。本质是 SRP 的长期侵蚀。\n\n**抽象地狱（Abstraction Hell）**\n\n强迫每个行为都有对应接口和实现，导致调用链过深。一个简单操作需要跨越多个间接层才能完成，接口数量远超实现数量。动机是\"面向接口编程\"，结果是可读性崩溃。\n\n> 反模式的共同根源：**把\"可能的变化\"当成了\"真实的变化\"来应对**，或者把设计原则当成了不加思考就必须遵守的规则。\n\n## 总结\n\n设计模式的价值，不在于提供一套可以直接套用的解法库，而在于培养一种**识别问题结构的认知能力**。\n\n记住 23 个模式的名字，远不如理解以下三件事：\n\n- **为什么模式会出现**：因为软件系统的变化是持续的，人类需要将应对变化的经验结构化、可传播\n- **模式在哪里有效**：只有当变化来源真实存在、上下文与模式的适用条件匹配时，模式才有意义\n- **模式的边界在哪里**：没有变化来源的地方不需要模式；模式本身也会随技术演进而弱化乃至消亡\n\n掌握设计模式，本质上是在建立一种**从问题出发识别结构**的思维方式——而不是从模式出发寻找应用场景。前者是工程判断力，后者是教条。\n\n> **设计模式是变化的产物，也是驯服变化的工具。真正理解它，是知道什么时候用，什么时候不用。**\n\n## 关联内容（自动生成）\n\n- [/软件工程/设计模式/行为模式.md](/软件工程/设计模式/行为模式.md) 涉及策略模式等具体的行为模式实现，与设计模式的核心概念密切相关\n- [/软件工程/设计模式/结构型模式.md](/软件工程/设计模式/结构型模式.md) 详细介绍了适配器等结构型模式，是设计模式体系的重要组成部分\n- [/软件工程/设计模式/创建型模式.md](/软件工程/设计模式/创建型模式.md) GoF 三大分类之一，与行为模式、结构型模式共同构成完整的模式体系\n- [/软件工程/软件设计/软件设计.md](/软件工程/软件设计/软件设计.md) 软件设计是设计模式的上层语境，设计模式是软件设计思想的结构化落地形式\n- [/软件工程/领域驱动设计.md](/软件工程/领域驱动设计.md) DDD 战术设计中的工厂、仓储、聚合根等概念直接对应 GoF 创建型与结构型模式\n- [/软件工程/软件设计/代码质量/代码重构.md](/软件工程/软件设计/代码质量/代码重构.md) 重构是模式落地的常见路径，\"Refactoring to Patterns\"是模式学习的重要实践方式\n- [/软件工程/架构模式/分层架构.md](/软件工程/架构模式/分层架构.md) 分层架构体现了关注点分离的设计思想，是模式在系统架构层面的重要承载形式\n- [/软件工程/微服务/微服务.md](/软件工程/微服务/微服务.md) 微服务的防腐层、服务边界划分等直接对应结构型模式的核心思想\n- [/编程语言/JAVA/高级/Servlet.md](/编程语言/JAVA/高级/Servlet.md) Servlet规范体现了模板方法、前端控制器等经典模式，是设计模式在Web技术中的典型应用\n- [/软件工程/架构模式/响应式架构.md](/软件工程/架构模式/响应式架构.md) 观察者模式是响应式架构的直接理论基础，两者在变化传播机制上高度关联\n","metadata":"tags: ['设计模式', '计算机系统', '软件工程']","hasMoreCommit":true,"totalCommits":22,"commitList":[{"date":"2026-03-11T16:22:40+08:00","author":"MY","message":"docs(design-patterns): 重构设计模式文档内容增强理论深度","hash":"73e3c22e7997681e79150457c0649ebfe5a92520"},{"date":"2026-03-02T10:15:03+08:00","author":"MY","message":"docs(SUMMARY): 更新文档目录结构并调整章节组织","hash":"291401ad85fb2dca108efed36ead29f7bbfe5ed8"},{"date":"2026-02-25T15:32:25+08:00","author":"MY","message":"docs(design-patterns): 移除章节编号优化文档结构","hash":"cf157d04f4f98f321798530edc00b4fa073c2184"},{"date":"2026-02-24T16:20:34+08:00","author":"MY","message":"docs(SUMMARY): 移除过时的框架文档链接","hash":"468d789997b9b5a69f7fe5ad9924e64e1890dd31"},{"date":"2026-02-12T14:07:03+08:00","author":"MY","message":"doc: 整理标签","hash":"290b3e8ad18f48832ac282290238d020fc030a88"},{"date":"2026-01-14T17:46:17+08:00","author":"MY","message":"docs(SUMMARY): 移除重复的AJAX文档引用","hash":"61a6fa3a3c2b1fee57724aefa49bc5512b017e5c"},{"date":"2025-11-25T19:38:46+08:00","author":"MY","message":"docs(设计模式): 完善设计模式文档内容与结构","hash":"753e665288f5b1121600fe2c3f839b202f31df29"},{"date":"2021-10-23T17:20:49+08:00","author":"My","message":"✏️链接修正","hash":"d2ab44299cc8cf7eb962f194ceb0d21bce3c70b2"},{"date":"2021-08-10T23:23:56+08:00","author":"MY","message":"✏️更新 设计模式","hash":"68359e9e189d5b4f16384cde4cdfcac0883c091a"},{"date":"2021-08-03T19:01:36+08:00","author":"cjiping","message":"📦整理 软件设计","hash":"73ec62cb807d110131e3ff2202e006535d2b8a00"}],"createTime":"2019-11-08T16:39:40+08:00"}