设计模式的本质

设计模式的本质,是在「变化」与「稳定」之间划界,让系统对扩展开放、对修改关闭。

几乎所有模式都在回答同一个问题:哪一部分将来最可能变?怎样让「变」不影响「不变」?

建议的学习顺序

#mermaid-svg-zM7CTIIAlhZlHRxo{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-zM7CTIIAlhZlHRxo .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-zM7CTIIAlhZlHRxo .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-zM7CTIIAlhZlHRxo .error-icon{fill:#552222;}#mermaid-svg-zM7CTIIAlhZlHRxo .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-zM7CTIIAlhZlHRxo .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-zM7CTIIAlhZlHRxo .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-zM7CTIIAlhZlHRxo .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-zM7CTIIAlhZlHRxo .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-zM7CTIIAlhZlHRxo .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-zM7CTIIAlhZlHRxo .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-zM7CTIIAlhZlHRxo .marker{fill:#333333;stroke:#333333;}#mermaid-svg-zM7CTIIAlhZlHRxo .marker.cross{stroke:#333333;}#mermaid-svg-zM7CTIIAlhZlHRxo svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-zM7CTIIAlhZlHRxo p{margin:0;}#mermaid-svg-zM7CTIIAlhZlHRxo .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-zM7CTIIAlhZlHRxo .cluster-label text{fill:#333;}#mermaid-svg-zM7CTIIAlhZlHRxo .cluster-label span{color:#333;}#mermaid-svg-zM7CTIIAlhZlHRxo .cluster-label span p{background-color:transparent;}#mermaid-svg-zM7CTIIAlhZlHRxo .label text,#mermaid-svg-zM7CTIIAlhZlHRxo span{fill:#333;color:#333;}#mermaid-svg-zM7CTIIAlhZlHRxo .node rect,#mermaid-svg-zM7CTIIAlhZlHRxo .node circle,#mermaid-svg-zM7CTIIAlhZlHRxo .node ellipse,#mermaid-svg-zM7CTIIAlhZlHRxo .node polygon,#mermaid-svg-zM7CTIIAlhZlHRxo .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-zM7CTIIAlhZlHRxo .rough-node .label text,#mermaid-svg-zM7CTIIAlhZlHRxo .node .label text,#mermaid-svg-zM7CTIIAlhZlHRxo .image-shape .label,#mermaid-svg-zM7CTIIAlhZlHRxo .icon-shape .label{text-anchor:middle;}#mermaid-svg-zM7CTIIAlhZlHRxo .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-zM7CTIIAlhZlHRxo .rough-node .label,#mermaid-svg-zM7CTIIAlhZlHRxo .node .label,#mermaid-svg-zM7CTIIAlhZlHRxo .image-shape .label,#mermaid-svg-zM7CTIIAlhZlHRxo .icon-shape .label{text-align:center;}#mermaid-svg-zM7CTIIAlhZlHRxo .node.clickable{cursor:pointer;}#mermaid-svg-zM7CTIIAlhZlHRxo .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-zM7CTIIAlhZlHRxo .arrowheadPath{fill:#333333;}#mermaid-svg-zM7CTIIAlhZlHRxo .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-zM7CTIIAlhZlHRxo .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-zM7CTIIAlhZlHRxo .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-zM7CTIIAlhZlHRxo .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-zM7CTIIAlhZlHRxo .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-zM7CTIIAlhZlHRxo .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-zM7CTIIAlhZlHRxo .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-zM7CTIIAlhZlHRxo .cluster text{fill:#333;}#mermaid-svg-zM7CTIIAlhZlHRxo .cluster span{color:#333;}#mermaid-svg-zM7CTIIAlhZlHRxo div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-zM7CTIIAlhZlHRxo .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-zM7CTIIAlhZlHRxo rect.text{fill:none;stroke-width:0;}#mermaid-svg-zM7CTIIAlhZlHRxo .icon-shape,#mermaid-svg-zM7CTIIAlhZlHRxo .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-zM7CTIIAlhZlHRxo .icon-shape p,#mermaid-svg-zM7CTIIAlhZlHRxo .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-zM7CTIIAlhZlHRxo .icon-shape .label rect,#mermaid-svg-zM7CTIIAlhZlHRxo .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-zM7CTIIAlhZlHRxo .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-zM7CTIIAlhZlHRxo .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-zM7CTIIAlhZlHRxo :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 设计原则
几种高频模式
读框架源码
自己项目小步重构
易混模式对照

高频模式建议优先:观察者、策略、工厂、组合、命令、装饰

它们覆盖了日常 80% 的「变化点」问题。其余模式在碰到具体问题时再查,完全来得及。


1. 模式不是语法,是「变化点管理术」

设计模式既不是库,也不是框架,更不是某种 C++ 语法糖。它是在反复出现的场景里,类与对象如何分工协作的命名经验。

模式 隔离的变化点
策略 可互换的算法
观察者 谁会响应状态变化
工厂 具体类型如何被创建
桥接 抽象与实现两个维度
装饰 动态叠加的职责
命令 请求的发起与执行

读模式时,先问「这里的变化点是什么」,比背 UML 更有用。


2. 三条底层逻辑

GoF 23 种模式背后,反复出现三条主线:

2.1 依赖抽象,不依赖具体

高层模块不应绑死在 new FileLogger() 上,而应依赖 Logger 接口。换实现时,调用方不动------依赖倒置(DIP),策略、工厂、桥接的共同地基。

2.2 组合优于继承

继承是白盒复用,子类与父类紧耦合。Has-A(持有一个策略、包一层装饰)是黑盒复用,往往更灵活。策略、装饰、桥接都在践行合成复用(CRP)

2.3 分离「做什么」与「谁来做 / 何时做」

分离什么 典型模式
算法 vs 使用算法的上下文 策略
请求 vs 执行者 命令
通知 vs 响应 观察者
构造 vs 使用 工厂、建造者
树形结构 vs 遍历方式 组合 + 迭代器

本质都是降低耦合、让职责更单一(SRP)。

先原则,再模式


3. 模式从「坏味道」反推,不是从空白纸画 UML

模式几乎总是重构的目标形状,而不是项目启动时的第一张架构图:

text 复制代码
满屏 if-else           → 策略 / 状态
类越来越大             → 单一职责 / 门面
继承树爆炸             → 桥接 / 组合 / 装饰
对象互相引用成网       → 中介者 / 观察者
创建逻辑散落各处       → 工厂 / 原型
撤销重做难做           → 命令 + 备忘录

会嗅坏味道,比会背 23 个名字更接近本质。


4. 模式是「角色关系」,不是固定类名

GoF 描述的是角色:Context、Strategy、ConcreteStrategy;Subject、Observer......

真实代码里可以叫 CheckoutPaymentStrategyAlipay------角色不变,命名随意

同一系统里常多个模式叠加:

  • 命令 + 备忘录 → 撤销栈
  • 组合 + 迭代器 → 遍历文档树
  • 工厂 + 单件 → 全局配置管理
  • 策略 + 模板方法 → 框架定流程、应用填步骤

模式的本质是可复用的微型架构片段


5. 三类模式:管三件不同的事

类型 本质问题 一句话
创建型 对象怎么来 new 从业务里挪走,隐藏构造复杂度
结构型 类怎么拼 用组合、包装、适配组织更大结构
行为型 职责怎么分、怎么通信 算法、状态、通知、请求如何流动

创建型管诞生 ,结构型管形状 ,行为型管动作与协作------这是对复杂度的三种切分。


6. 模式有代价:用复杂换灵活

每种模式都带来:

  • 更多的类与接口
  • 更多的间接层
  • 更高的理解成本

因此模式的另一面是:有意识地接受一定复杂度,换取未来的可扩展性

简单问题用简单解法;模式不是勋章,是在确认真有变化压力时的投资


7. 模式 vs 框架 vs 语言

设计模式 框架(Qt / VTK) 现代 C++
是什么 设计经验的名字 已实现的大结构 语言级抽象
例子 策略、观察者 信号槽、vtkInteractorStyle std::function、RAII
关系 思想层 模式已嵌入 API 可简化实现,思想仍在
  • STL 迭代器 = 迭代器模式的标准化
  • std::function = 轻量策略 / 命令
  • Qt 信号槽 = 观察者思想的框架化
  • vtkCommand = Observer 回调载体(名字像 Command,语义不是 GoF 命令,见 VTK 专题

本质在思想;形态随语言与框架演进。


重点与注意(速记)

重点 :模式 = 变化点隔离 + 依赖抽象 + 组合复用 的命名结构。

重点 :从坏味道出发重构,比一上来「模式驱动设计」更务实。

注意 :模式是角色关系,可叠加;不是每个类只能戴一顶帽子。

注意:框架里已内置大量模式;读 API 也是在读模式落地。

相关推荐
折哥的程序人生 · 物流技术专研11 小时前
第8篇:六大设计原则在工厂模式中的体现
java·设计模式·设计原则·工厂模式·编程进阶·扩充系列
咖啡八杯12 小时前
GoF设计模式——模板方法模式
java·后端·spring·设计模式
饼干哥哥1 天前
Openclaw已死?任何Agent都能用Cli实现AI自主运营跨境电商
设计模式·openai·ai编程
折哥的程序人生 · 物流技术专研1 天前
第4篇:抽象工厂模式——产品族一键创建
java·设计模式·抽象工厂模式·创建型模式·编程进阶·产品族·扩充系列
geovindu2 天前
go: Cascading Failures Pattern
开发语言·后端·设计模式·golang·反模式·级联失效反模式
端庄的战斗机2 天前
javascript 设计模式(文章很长,请自备瓜子,水果和眼药水)
开发语言·javascript·设计模式
饼干哥哥2 天前
我开发了一个「吃掉」别人Skill来升级的饕餮.Skill,现在免费开源
人工智能·设计模式·开源
CaffeinePro2 天前
什么是系统架构?架构师到底在做什么?
设计模式·架构
AI人工智能+电脑小能手2 天前
【大白话说Java面试题 第156题】【06_Spring篇】第16题:Spring 用到了哪些设计模式?
java·spring·设计模式·代理模式·工厂模式