设计模式概述

134 阅读15分钟

设计模式分为创建型、结构型和行为型,通过解耦对象创建、接口适配及职责分配,提升代码复用性和可维护性,遵循开闭原则等核心思想,优化系统扩展性。

概述


一、创建型模式(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())。

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接口)。

17. 中介者模式(Mediator Pattern)

  • 定义:集中管理对象间交互,减少直接依赖。

  • 优点

    • 降低对象间耦合,简化协作逻辑。
  • 缺点

    • 中介者可能成为瓶颈。
  • 解决方案

    • 分层设计中介者,避免职责过重。

18. 备忘录模式(Memento Pattern)

  • 定义:捕获对象状态,支持恢复。

  • 优点

    • 无侵入式保存状态,符合封装原则。
  • 缺点

    • 内存占用可能较大。
  • 解决方案

    • 结合序列化压缩状态数据。

19. 观察者模式(Observer Pattern)

  • 定义:一对多依赖关系,状态变化自动通知。

  • 优点

    • 解耦观察者与被观察者,支持动态订阅/取消。
  • 缺点

    • 通知机制可能引发循环依赖。
  • 解决方案

    • 使用.NET的IObservable<T>IObserver<T>接口实现(如Reactive Extensions)。

20. 状态模式(State Pattern)

  • 定义:对象行为基于内部状态变化。

  • 优点

    • 状态转换清晰,避免条件判断冗余。
  • 缺点

    • 状态类数量可能过多。
  • 解决方案

    • 使用策略模式(Strategy)替代简单状态逻辑。

21. 策略模式(Strategy Pattern)

  • 定义:定义算法族,动态切换算法。

  • 优点

    • 算法可替换,符合“开闭原则”。
  • 缺点

    • 需为每种算法创建类。
  • 解决方案

    • 使用Lambda表达式或匿名类简化实现。

22. 模板方法模式(Template Method Pattern)

  • 定义:定义算法骨架,子类实现具体步骤。

  • 优点

    • 提供统一框架,强制子类遵循结构。
  • 缺点

    • 父类过度控制可能限制灵活性。
  • 解决方案

    • 使用钩子方法(Hook)允许子类选择性覆盖。

23. 访问者模式(Visitor Pattern)

  • 定义:在不改变元素类的情况下,定义新的操作。

  • 优点

    • 扩展操作而不修改元素类。
  • 缺点

    • 违反“开闭原则”,新增元素需修改访问者接口。
  • 解决方案

    • 结合反射或动态代理减少硬编码。

总结与建议

  1. 选择模式的关键

    • 根据需求场景选择(如需创建对象选工厂,需解耦选观察者)。
    • 平衡复杂度与可维护性,避免过度设计。
  2. 设计原则

    • 单一职责原则:每个类只负责一个功能。
    • 开闭原则:对扩展开放,对修改关闭。
    • 里氏替换原则:子类可替换父类而不影响程序正确性。
  3. 常见问题解决方案

    • 全局状态:使用依赖注入替代单例。
    • 复杂性:结合反射或工厂模式动态创建对象。
    • 扩展性:优先使用策略或模板方法模式。

希望这些内容能帮助你更系统地理解和应用设计模式!

总结


以下是补充了应用场景的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)在不改变元素类的情况下,定义新的操作。扩展操作而不修改元素类。违反开闭原则,新增元素需修改访问者接口。结合反射或动态代理减少硬编码。对象结构的多种操作(如计算几何图形面积/周长)、不同数据类型的处理。