3.《设计模式》:软件设计与解耦能力提炼

第三阶段学习目标:理解常见的软件设计问题,以及如何使用抽象、组合、接口和多态控制复杂度。

核心思想:

不要背设计模式,要理解"为什么需要这种设计"。


目录

  • [1. 设计模式到底解决什么?](#1. 设计模式到底解决什么?)
  • [2. 第一原则:组合优于继承](#2. 第一原则:组合优于继承)
  • [3. Strategy:策略模式](#3. Strategy:策略模式)
  • [4. Factory:工厂模式](#4. Factory:工厂模式)
  • [5. Adapter:适配器模式](#5. Adapter:适配器模式)
  • [6. Facade:外观模式](#6. Facade:外观模式)
  • [7. Observer:观察者 / 事件模式](#7. Observer:观察者 / 事件模式)
  • [8. Command:命令模式](#8. Command:命令模式)
  • [9. State:状态模式](#9. State:状态模式)
  • [10. Dependency Injection:依赖注入](#10. Dependency Injection:依赖注入)
  • [11. 设计模式真正应该学习什么?](#11. 设计模式真正应该学习什么?)
  • [12. 设计模式的反模式](#12. 设计模式的反模式)
  • [13. AI Coding 中如何使用设计模式?](#13. AI Coding 中如何使用设计模式?)
  • [14. 本阶段最终能力](#14. 本阶段最终能力)

1. 设计模式到底解决什么?

设计模式不是为了让代码显得高级。

它解决的是反复出现的软件设计问题:

text 复制代码
需求变化
 ↓
代码结构开始复杂
 ↓
找到变化点
 ↓
隔离变化
 ↓
减少影响范围

所以设计模式与前面的"高内聚、低耦合、封装变化"是一脉相承的。


2. 第一原则:组合优于继承

不要看到不同类型就马上建立复杂继承树。

很多时候:

text 复制代码
继承

容易形成强耦合。

而:

text 复制代码
组合

更灵活。

例如:

text 复制代码
ModelService
 ├── Loader
 ├── Cache
 ├── CoordinateTransformer
 └── Logger

ModelService 通过组合获得能力。


3. Strategy:策略模式

适合:

同一个业务流程存在多个可替换算法 / 实现。

例如 GIS 模型加载:

text 复制代码
ModelLoader
 ├── OSGBLoader
 ├── Tiles3DLoader
 ├── GLTFLoader
 └── OBJLoader

上层只依赖:

text 复制代码
ModelLoader

4. Factory:工厂模式

适合:

创建对象的逻辑比较复杂,或者创建过程需要根据类型选择实现。

例如:

text 复制代码
createModelLoader(type)

根据:

text 复制代码
"osgb"
"3dtiles"
"gltf"

返回不同 Loader。

注意:

简单对象不要为了"设计模式"强行使用 Factory。


5. Adapter:适配器模式

适合:

两个接口不兼容,但你希望它们能够协作。

例如:

text 复制代码
你的业务接口
     ↓
ModelLoader
     ↓
第三方 GIS SDK

如果第三方 SDK 的接口与你的业务接口不同,可以通过 Adapter 转换。


6. Facade:外观模式

适合:

一个复杂系统对外只需要暴露一个简单入口。

例如:

text 复制代码
GISFacade

内部:

text 复制代码
SceneManager
ModelManager
TerrainManager
CameraManager
CoordinateService

外部只需要:

text 复制代码
gis.loadProject()

7. Observer:观察者 / 事件模式

适合:

一个事件发生后,多个模块需要响应,但不希望它们互相直接依赖。

例如:

text 复制代码
ModelService
    ↓
model:loaded
    ↓
 ┌──────────┬──────────┐
 ↓          ↓          ↓
UI       Logger    SceneManager

非常适合:

  • Electron
  • 前端
  • 状态变化
  • GIS 场景事件
  • 异步任务

8. Command:命令模式

把:

"一个操作"

封装成对象或独立命令。

例如:

text 复制代码
LoadModelCommand
RemoveModelCommand
MoveModelCommand

适合进一步实现:

  • Undo
  • Redo
  • 操作记录
  • 批量执行
  • 命令队列

GIS 编辑类软件尤其值得理解。


9. State:状态模式

当一个对象的行为会随着状态变化而变化时,可以显式建模状态。

例如:

text 复制代码
Model
 ├── Idle
 ├── Loading
 ├── Loaded
 ├── Failed
 └── Disposed

这比到处使用:

text 复制代码
isLoading
isLoaded
isError

更容易控制复杂度。


10. Dependency Injection:依赖注入

核心思想:

不要让一个模块自己决定所有依赖。

例如不推荐:

text 复制代码
ModelService
 ↓
new CesiumModelLoader()

可以考虑:

text 复制代码
ModelService
 ↓
ModelLoader

然后外部注入:

text 复制代码
ModelService(loader)

这样测试时可以传:

text 复制代码
FakeModelLoader

从而降低耦合、提高可测试性。


11. 设计模式真正应该学习什么?

不要记:

text 复制代码
Strategy = 策略
Factory = 工厂
Observer = 观察者

而要记:

text 复制代码
什么问题?
 ↓
什么变化?
 ↓
哪里耦合?
 ↓
如何隔离?

例如:

为什么使用 Strategy?

不是因为:

"Strategy 是经典设计模式。"

而是因为:

这里有多个可替换算法,而且未来可能继续增加。


12. 设计模式的反模式

常见错误:

text 复制代码
简单问题
 ↓
硬套设计模式
 ↓
Factory + AbstractFactory + Strategy + Adapter
 ↓
代码复杂度暴涨

最终:

设计模式解决的问题比原来的问题还复杂。

所以应该遵循:

先有问题,再有模式。


13. AI Coding 中如何使用设计模式?

不要问:

text 复制代码
"这里帮我用设计模式优化。"

更好的问法:

text 复制代码
当前代码存在多个模型格式。

请分析:
1. 这些实现有哪些变化点?
2. 是否存在高耦合?
3. Strategy / Factory / Adapter 哪种更适合?
4. 是否真的有必要引入设计模式?
5. 最简单的方案是什么?

这会训练你的设计判断能力。


14. 本阶段最终能力

能够看到一个问题时自然思考:

text 复制代码
这里什么会变化?
       ↓
能不能封装?
       ↓
能不能通过接口隔离?
       ↓
能不能通过组合降低耦合?
       ↓
有没有必要使用某种设计模式?

最终目标:

不是会背设计模式,而是会识别设计问题。

相关推荐
墨子夕1 小时前
设计模式——Java × Python 双语言精讲 · 23 个经典模式 + 现代演进(前言篇)
java·开发语言·设计模式
墨子夕3 小时前
设计模式——Java × Python 双语言精讲 · 23 个经典模式 + 现代演进(第一篇)
java·python·设计模式
General_G5 小时前
创建型模式—原型(Prototype)模式
c++·设计模式·原型模式
geovindu7 小时前
rust: Template Method Pattern
开发语言·后端·设计模式·rust·行为模式·模板方法模
geovindu9 小时前
rust: Template Method Pattern(续)
开发语言·后端·设计模式·rust·行为模式·板方法模式
博风10 小时前
17、设计模式应用举例:单件模式:多线程争冠军
设计模式
高晶1 天前
无乘法器实现LC二阶滤波器:基于移位运算的快速算法与四种精度推导
算法·设计模式·程序员
高晶1 天前
主从自动分配算法:平均值乘以设备数一半的选举基准值解析
算法·设计模式·程序员
延晗1 天前
【从零开始 DeepSeek Harness 插件开发教程】二、一切皆插件:简单理解一下 Cordis 内核与 DSH 心智模型
设计模式·deepseek
高晶1 天前
Android 通讯录应用开发实战:从零搭建 SQLite 数据持久化完整项目
android·设计模式·前端框架