设计模式分为创建型、结构型和行为型,通过解耦对象创建、接口适配及职责分配,提升代码复用性和可维护性,遵循开闭原则等核心思想,优化系统扩展性。
概述
一、创建型模式(Creational Patterns)
1. 单例模式(Singleton Pattern)
-
定义:确保一个类只有一个实例,并提供全局访问点。
-
优点:
- 节省资源,避免重复创建对象。
- 提供全局访问点,简化调用。
-
缺点:
- 引入全局状态,可能导致代码难以测试和维护。
- 违反“开闭原则”,扩展性差。
-
解决方案:
- 使用依赖注入(DI)替代直接访问单例对象,增强可测试性和灵活性。
- 通过多例模式(Multi-Ton)扩展,支持多个实例。
2. 工厂模式(Factory Pattern)
-
定义:封装对象的创建逻辑,客户端无需直接调用
new。 -
优点:
- 客户端与具体类解耦,易于扩展。
- 统一对象创建,简化客户端代码。
-
缺点:
- 增加代码复杂度,需额外的工厂类。
- 难以支持动态创建新类型。
-
解决方案:
- 使用抽象工厂模式(Abstract Factory)抽象化工厂接口,支持多产品族。
- 结合反射或依赖注入动态创建对象。
3. 抽象工厂模式(Abstract Factory Pattern)
-
定义:提供一个接口来创建相关对象家族,无需指定具体类。
-
优点:
- 客户端与具体类完全解耦,支持多产品族。
- 灵活切换产品族(如不同平台的UI组件)。
-
缺点:
- 难以支持新增产品类型,需修改接口。
- 复杂度较高,需维护多个工厂类。
-
解决方案:
- 使用反射或依赖注入动态创建产品实例。
- 通过扩展接口逐步添加新类型,而非修改现有代码。
4. 建造者模式(Builder Pattern)
-
定义:将复杂对象的构建与表示分离,支持分步骤构建。
-
优点:
- 解耦构建逻辑与表示,灵活扩展构建步骤。
- 适合创建复杂对象(如配置、文档)。
-
缺点:
- 需要定义多个类(Director、Builder、ConcreteBuilder),代码量增加。
-
解决方案:
- 使用流畅接口(Fluent Interface) ,通过链式调用简化构建过程(如
builder.addA().addB())。
- 使用流畅接口(Fluent Interface) ,通过链式调用简化构建过程(如
5. 原型模式(Prototype Pattern)
-
定义:通过复制现有实例创建新对象,避免重复初始化。
-
优点:
- 快速克隆对象,提高性能。
- 适合复杂对象的创建(如数据库连接池)。
-
缺点:
- 需要深拷贝支持,可能引入内存问题。
-
解决方案:
- 使用序列化或反射实现深拷贝。
- 确保原型对象的可克隆性(如实现
Cloneable接口)。
二、结构型模式(Structural Patterns)
6. 适配器模式(Adapter Pattern)
-
定义:将不兼容接口转换为客户端期望的接口。
-
优点:
- 兼容旧系统或第三方库,复用现有代码。
- 无需修改原有类,降低耦合。
-
缺点:
- 需要额外适配器类,增加代码复杂度。
-
解决方案:
- 使用接口适配器模式(默认方法)减少适配器数量(如Java 8的默认方法)。
7. 桥接模式(Bridge Pattern)
-
定义:将抽象与实现分离,使其可独立扩展。
-
优点:
- 避免“爆炸式类继承”,支持动态切换实现。
- 适用于多维度变化(如形状与颜色的组合)。
-
缺点:
- 需要设计抽象接口和实现类,初期复杂度较高。
-
解决方案:
- 使用组合(Composition)替代继承,实现抽象与实现的解耦。
8. 组合模式(Composite Pattern)
-
定义:将对象组合成树形结构,统一处理单个对象和组合对象。
-
优点:
- 客户端无需关心对象是单个还是组合,简化操作。
- 递归处理复杂结构(如文件系统、组织架构)。
-
缺点:
- 可能过度设计,限制组合对象的类型。
-
解决方案:
- 通过接口定义组合对象,允许动态添加或移除子节点。
9. 装饰器模式(Decorator Pattern)
-
定义:动态为对象添加职责,通过组合扩展功能。
-
优点:
- 灵活扩展对象功能,优于继承。
- 符合“开闭原则”。
-
缺点:
- 层级过深可能导致性能问题。
-
解决方案:
- 使用代理(Proxy)或组合模式替代,避免过度装饰。
10. 外观模式(Facade Pattern)
-
定义:为复杂子系统提供统一的简化接口。
-
优点:
- 简化客户端调用,隐藏内部复杂性。
- 提高系统可维护性。
-
缺点:
- 可能导致外观类职责过重。
-
解决方案:
- 分层设计外观类,避免单点依赖。
11. 享元模式(Flyweight Pattern)
-
定义:共享细粒度对象,减少内存消耗。
-
优点:
- 节省内存,适用于大量对象场景(如文本编辑器、游戏)。
-
缺点:
- 需要外部存储状态,增加代码复杂度。
-
解决方案:
- 结合工厂模式管理共享对象池。
12. 代理模式(Proxy Pattern)
-
定义:为其他对象提供代理,控制访问或增强功能。
-
优点:
- 支持远程访问(远程代理)、延迟加载(虚代理)等。
- 解耦客户端与真实对象。
-
缺点:
- 增加网络延迟(远程代理)。
-
解决方案:
- 使用智能指针(Smart Pointer)管理代理生命周期。
三、行为型模式(Behavioral Patterns)
13. 责任链模式(Chain of Responsibility Pattern)
-
定义:请求沿责任链传递,多个对象有机会处理。
-
优点:
- 解耦请求发送者与处理者,灵活扩展处理逻辑。
-
缺点:
- 可能无对象处理请求,需默认处理。
-
解决方案:
- 设置最终处理者或日志记录未处理请求。
14. 命令模式(Command Pattern)
-
定义:将请求封装为对象,支持参数化和队列化。
-
优点:
- 支持撤销/重做(Undo/Redo)、日志记录、队列执行。
-
缺点:
- 增加命令对象数量。
-
解决方案:
- 结合策略模式定义具体命令行为。
15. 解释器模式(Interpreter Pattern)
-
定义:为语言定义文法,并解释句子含义。
-
优点:
- 灵活扩展语言规则,适合小型语法解析。
-
缺点:
- 复杂语法导致性能问题。
-
解决方案:
- 使用解析器生成器(如ANTLR)替代手动实现。
16. 迭代器模式(Iterator Pattern)
-
定义:提供统一接口访问聚合对象内部元素。
-
优点:
- 解耦聚合对象与遍历逻辑,支持多种遍历方式。
-
缺点:
- 需为每种聚合实现迭代器。
-
解决方案:
- 使用内置迭代器(如Java的
Iterable接口)。
- 使用内置迭代器(如Java的
17. 中介者模式(Mediator Pattern)
-
定义:集中管理对象间交互,减少直接依赖。
-
优点:
- 降低对象间耦合,简化协作逻辑。
-
缺点:
- 中介者可能成为瓶颈。
-
解决方案:
- 分层设计中介者,避免职责过重。
18. 备忘录模式(Memento Pattern)
-
定义:捕获对象状态,支持恢复。
-
优点:
- 无侵入式保存状态,符合封装原则。
-
缺点:
- 内存占用可能较大。
-
解决方案:
- 结合序列化压缩状态数据。
19. 观察者模式(Observer Pattern)
-
定义:一对多依赖关系,状态变化自动通知。
-
优点:
- 解耦观察者与被观察者,支持动态订阅/取消。
-
缺点:
- 通知机制可能引发循环依赖。
-
解决方案:
- 使用.NET的
IObservable<T>和IObserver<T>接口实现(如Reactive Extensions)。
- 使用.NET的
20. 状态模式(State Pattern)
-
定义:对象行为基于内部状态变化。
-
优点:
- 状态转换清晰,避免条件判断冗余。
-
缺点:
- 状态类数量可能过多。
-
解决方案:
- 使用策略模式(Strategy)替代简单状态逻辑。
21. 策略模式(Strategy Pattern)
-
定义:定义算法族,动态切换算法。
-
优点:
- 算法可替换,符合“开闭原则”。
-
缺点:
- 需为每种算法创建类。
-
解决方案:
- 使用Lambda表达式或匿名类简化实现。
22. 模板方法模式(Template Method Pattern)
-
定义:定义算法骨架,子类实现具体步骤。
-
优点:
- 提供统一框架,强制子类遵循结构。
-
缺点:
- 父类过度控制可能限制灵活性。
-
解决方案:
- 使用钩子方法(Hook)允许子类选择性覆盖。
23. 访问者模式(Visitor Pattern)
-
定义:在不改变元素类的情况下,定义新的操作。
-
优点:
- 扩展操作而不修改元素类。
-
缺点:
- 违反“开闭原则”,新增元素需修改访问者接口。
-
解决方案:
- 结合反射或动态代理减少硬编码。
总结与建议
-
选择模式的关键:
- 根据需求场景选择(如需创建对象选工厂,需解耦选观察者)。
- 平衡复杂度与可维护性,避免过度设计。
-
设计原则:
- 单一职责原则:每个类只负责一个功能。
- 开闭原则:对扩展开放,对修改关闭。
- 里氏替换原则:子类可替换父类而不影响程序正确性。
-
常见问题解决方案:
- 全局状态:使用依赖注入替代单例。
- 复杂性:结合反射或工厂模式动态创建对象。
- 扩展性:优先使用策略或模板方法模式。
希望这些内容能帮助你更系统地理解和应用设计模式!
总结
以下是补充了应用场景的23种设计模式表格总结,按分类整理:
一、创建型模式(Creational Patterns)
| 分类 | 模式名称 | 定义 | 优点 | 缺点 | 解决方案 | 应用场景 |
|---|---|---|---|---|---|---|
| 创建型 | 单例模式(Singleton) | 确保一个类只有一个实例,提供全局访问点。 | 节省资源,简化调用。 | 引入全局状态,难以测试。 | 使用依赖注入或多例模式替代。 | 数据库连接池、日志记录器、配置管理器、缓存管理。 |
| 创建型 | 工厂模式(Factory) | 封装对象创建逻辑,客户端无需直接调用new。 | 解耦客户端与具体类,易于扩展。 | 增加代码复杂度,难以动态创建新类型。 | 结合抽象工厂或反射动态创建对象。 | 创建不同类型的按钮(如圆形按钮、方形按钮)、不同数据库驱动(MySQL/Oracle)。 |
| 创建型 | 抽象工厂模式 | 提供接口创建相关对象家族,无需指定具体类。 | 客户端与具体类完全解耦,支持多产品族。 | 难以支持新增产品类型,复杂度高。 | 使用反射或依赖注入动态创建产品实例。 | 跨平台UI组件(如Windows/Linux不同界面)、不同版本的API接口。 |
| 创建型 | 建造者模式(Builder) | 分离复杂对象的构建与表示,支持分步骤构建。 | 解耦构建逻辑与表示,灵活扩展。 | 需要定义多个类,代码量增加。 | 使用流畅接口(Fluent Interface)简化构建过程。 | 构建复杂对象(如配置文件、文档生成、订单构建)。 |
| 创建型 | 原型模式(Prototype) | 通过复制现有实例创建新对象,避免重复初始化。 | 快速克隆对象,提高性能。 | 需要深拷贝支持,可能引入内存问题。 | 使用序列化或反射实现深拷贝。 | 对象池管理(如网络连接池)、快速复制对象状态(如游戏中的敌人克隆)。 |
二、结构型模式(Structural Patterns)
| 分类 | 模式名称 | 定义 | 优点 | 缺点 | 解决方案 | 应用场景 |
|---|---|---|---|---|---|---|
| 结构型 | 适配器模式(Adapter) | 将不兼容接口转换为客户端期望的接口。 | 兼容旧系统,复用现有代码。 | 需要额外适配器类,增加复杂度。 | 使用接口适配器模式(默认方法)减少适配器数量。 | 适配不同支付接口(如支付宝/微信支付)、适配旧系统API与新系统对接。 |
| 结构型 | 桥接模式(Bridge) | 分离抽象与实现,使其可独立扩展。 | 避免“爆炸式继承”,支持动态切换实现。 | 初期设计复杂度高。 | 使用组合(Composition)替代继承,实现解耦。 | 图形库中分离形状与颜色(如不同渲染引擎支持不同形状)、操作系统与硬件驱动。 |
| 结构型 | 组合模式(Composite) | 将对象组合成树形结构,统一处理单个对象和组合对象。 | 客户端无需关心对象类型,简化操作。 | 可能过度设计,限制组合对象类型。 | 通过接口定义组合对象,允许动态添加/移除子节点。 | 文件系统(文件与文件夹)、组织架构(员工与部门)、游戏中的角色与装备。 |
| 结构型 | 装饰器模式(Decorator) | 动态为对象添加职责,通过组合扩展功能。 | 灵活扩展功能,符合开闭原则。 | 层级过深可能导致性能问题。 | 使用代理或组合模式替代,避免过度装饰。 | 增加咖啡订单功能(如加奶/加糖)、网络请求的拦截器(如添加日志或认证头)。 |
| 结构型 | 外观模式(Facade) | 为复杂子系统提供统一的简化接口。 | 简化客户端调用,隐藏内部复杂性。 | 外观类职责可能过重。 | 分层设计外观类,避免单点依赖。 | 数据库事务管理(封装多表操作)、第三方API的封装(如整合多个支付接口)。 |
| 结构型 | 享元模式(Flyweight) | 共享细粒度对象,减少内存消耗。 | 节省内存,适用于大量对象场景。 | 需要外部存储状态,增加代码复杂度。 | 结合工厂模式管理共享对象池。 | 文本编辑器中的字符共享、游戏中的重复角色或物品。 |
| 结构型 | 代理模式(Proxy) | 为其他对象提供代理,控制访问或增强功能。 | 支持远程访问、延迟加载等,解耦客户端与真实对象。 | 远程代理可能增加网络延迟。 | 使用智能指针(Smart Pointer)管理代理生命周期。 | 远程服务调用(如RPC)、图像加载的延迟加载、安全权限验证(如访问控制)。 |
三、行为型模式(Behavioral Patterns)
| 分类 | 模式名称 | 定义 | 优点 | 缺点 | 解决方案 | 应用场景 |
|---|---|---|---|---|---|---|
| 行为型 | 责任链模式(Chain of Responsibility) | 请求沿责任链传递,多个对象有机会处理。 | 解耦请求发送者与处理者,灵活扩展处理逻辑。 | 可能无对象处理请求,需默认处理。 | 设置最终处理者或日志记录未处理请求。 | 日志记录的分级处理(如ERROR/WARNING/INFO)、权限验证(多个过滤器)。 |
| 行为型 | 命令模式(Command) | 将请求封装为对象,支持参数化和队列化。 | 支持撤销/重做、日志记录、队列执行。 | 增加命令对象数量。 | 结合策略模式定义具体命令行为。 | 命令行工具、Undo/Redo功能(如文本编辑器)、事务回滚。 |
| 行为型 | 解释器模式(Interpreter) | 为语言定义文法,并解释句子含义。 | 灵活扩展语言规则,适合小型语法解析。 | 复杂语法导致性能问题。 | 使用解析器生成器(如ANTLR)替代手动实现。 | 简单的配置文件解析(如INI文件)、表达式求值(如计算器)。 |
| 行为型 | 迭代器模式(Iterator) | 提供统一接口访问聚合对象内部元素。 | 解耦聚合对象与遍历逻辑,支持多种遍历方式。 | 需为每种聚合实现迭代器。 | 使用内置迭代器(如Java的Iterable接口)。 | 集合框架(如List/Set的遍历)、自定义数据结构的遍历。 |
| 行为型 | 中介者模式(Mediator) | 集中管理对象间交互,减少直接依赖。 | 降低对象间耦合,简化协作逻辑。 | 中介者可能成为瓶颈。 | 分层设计中介者,避免职责过重。 | 复杂的窗体交互(如多个控件联动)、多人协作系统(如聊天室消息处理)。 |
| 行为型 | 备忘录模式(Memento) | 捕获对象状态,支持恢复。 | 无侵入式保存状态,符合封装原则。 | 内存占用可能较大。 | 结合序列化压缩状态数据。 | 游戏存档恢复、编辑器的撤销操作、事务状态保存。 |
| 行为型 | 观察者模式(Observer) | 一对多依赖关系,状态变化自动通知。 | 解耦观察者与被观察者,支持动态订阅/取消。 | 通知机制可能引发循环依赖。 | 使用.NET的IObservable<T>和IObserver<T>接口实现(如Reactive Extensions)。 | 实时数据更新(如股票价格通知)、事件驱动系统(如UI事件监听)。 |
| 行为型 | 状态模式(State) | 对象行为基于内部状态变化。 | 状态转换清晰,避免条件判断冗余。 | 状态类数量可能过多。 | 使用策略模式(Strategy)替代简单状态逻辑。 | 游戏角色状态(如行走/攻击/死亡)、订单状态机(如待支付/已发货/已完成)。 |
| 行为型 | 策略模式(Strategy) | 定义算法族,动态切换算法。 | 算法可替换,符合开闭原则。 | 需为每种算法创建类。 | 使用Lambda表达式或匿名类简化实现。 | 支付方式选择(支付宝/微信/信用卡)、排序算法切换(冒泡/快速排序)。 |
| 行为型 | 模板方法模式(Template Method) | 定义算法骨架,子类实现具体步骤。 | 提供统一框架,强制子类遵循结构。 | 父类过度控制可能限制灵活性。 | 使用钩子方法(Hook)允许子类选择性覆盖。 | 业务流程框架(如订单处理流程)、算法骨架(如排序算法的主框架)。 |
| 行为型 | 访问者模式(Visitor) | 在不改变元素类的情况下,定义新的操作。 | 扩展操作而不修改元素类。 | 违反开闭原则,新增元素需修改访问者接口。 | 结合反射或动态代理减少硬编码。 | 对象结构的多种操作(如计算几何图形面积/周长)、不同数据类型的处理。 |