23种设计模式
本文最后更新于:2025年2月18日 下午
23种设计模式
按问题类型划分
1. 创建型设计模式(解决对象创建过程中的问题)
这些设计模式关注如何创建对象,确保系统在创建对象时具备灵活性和可扩展性,减少对象创建时的复杂度。
- 单例模式 (Singleton)
问题:需要确保一个类只有一个实例,并提供全局访问点。
解决:通过控制实例的创建过程来保证类只有一个实例。 - 工厂方法模式 (Factory Method)
问题:不知道在运行时需要创建哪些类的实例。
解决:通过定义一个创建对象的接口,让子类决定实例化哪个类。 - 抽象工厂模式 (Abstract Factory)
问题:需要创建一组相关的对象,但不想指定它们的具体类。
解决:提供一个接口来创建一系列相关或依赖的对象,而不具体指定它们的类。 - 建造者模式 (Builder)
问题:创建一个复杂对象时,构建过程非常复杂,或者创建过程中的多个步骤独立。
解决:通过分步构建,逐步创建复杂的对象。 - 原型模式 (Prototype)
问题:创建新对象时性能较低或对象创建比较复杂。
解决:通过克隆现有对象来创建新对象,避免重复的创建操作。
2. 结构型设计模式(解决类或对象之间的关系问题)
这些模式主要处理类或对象的组成方式,帮助设计更加高效、灵活的系统结构。
- 适配器模式 (Adapter)
问题:需要使用某个现有的接口,但它的接口与当前系统不兼容。
解决:通过创建一个适配器类,将现有接口转换为需要的接口。 - 桥接模式 (Bridge)
问题:在不同的维度上扩展类(如功能与实现分离)时,导致类的数量急剧增加。
解决:将功能和实现分离,让它们独立变化,从而降低系统复杂性。 - 组合模式 (Composite)
问题:处理部分与整体的层级结构时。
解决:通过将对象组合成树形结构,使得客户端可以一致地对待单个对象和组合对象。 - 装饰器模式 (Decorator)
问题:需要动态地为对象添加职责,但不能通过继承来扩展。
解决:通过包装原始对象,动态添加新的功能。 - 外观模式 (Facade)
问题:系统中的子系统复杂且不易使用。
解决:提供一个统一的接口,简化子系统的操作。 - 享元模式 (Flyweight)
问题:对象数量过多,导致内存消耗过大。
解决:通过共享已存在的对象来减少内存消耗。 - 代理模式 (Proxy)
问题:控制对一个对象的访问,提供对某个对象的间接访问。
解决:通过代理对象控制对目标对象的访问(可以是延迟加载、访问控制等)。
3. 行为型设计模式(解决对象之间的交互和职责分配问题)
这些设计模式主要关注类与类之间如何交互,如何分配责任,以及如何使得对象之间的交互更加灵活和解耦。
- 责任链模式 (Chain of Responsibility)
问题:请求的处理者不确定,或者处理者的顺序不确定。
解决:通过创建一个链表结构的处理对象,让每个对象负责处理特定的请求,直到某个对象处理完毕。 - 命令模式 (Command)
问题:请求的发送者和请求的接收者之间高度耦合。
解决:将请求封装成一个命令对象,从而解耦请求的发送者和接收者。 - 解释器模式 (Interpreter)
问题:需要对语言进行解析和解释。
解决:为特定的语言或表达式创建解释器,通过定义文法规则来解释和计算输入。 - 迭代器模式 (Iterator)
问题:需要遍历一个容器中的元素,而不暴露容器的内部结构。
解决:提供一个迭代器对象,允许客户端按顺序访问集合元素。 - 中介者模式 (Mediator)
问题:多个对象之间有复杂的交互,导致系统非常复杂。
解决:通过引入中介者对象,所有的交互都通过中介者进行,从而简化对象之间的关系。 - 备忘录模式 (Memento)
问题:需要保存和恢复对象的状态,但又不能暴露对象的内部结构。
解决:通过备忘录对象保存对象的状态,以便以后恢复。 - 观察者模式 (Observer)
问题:一个对象的状态变化需要通知其他依赖的对象。
解决:定义一种一对多的依赖关系,当一个对象的状态发生变化时,所有依赖它的对象都会自动得到通知。 - 状态模式 (State)
问题:一个对象的行为取决于它的状态,而且状态之间的切换逻辑较为复杂。
解决:通过将不同的状态抽象为状态对象,每个状态对象定义自己的行为,并在状态之间进行切换。 - 策略模式 (Strategy)
问题:需要根据不同的条件选择不同的算法或行为。
解决:将每个算法或行为封装成一个策略对象,客户端可以根据需要选择不同的策略。 - 模板方法模式 (Template Method)
问题:子类需要按照特定顺序执行一些步骤,但这些步骤中的某些操作是可变的。
解决:通过在父类中定义一个模板方法,调用一些可变的步骤,由子类来实现具体的步骤。 - 访问者模式 (Visitor)
问题:对象结构中的元素需要不同的操作,但它们通常很难扩展。
解决:通过访问者对象来定义对不同元素的操作,将操作与对象结构解耦。
总结
- 创建型模式:主要解决对象创建的问题。
- 结构型模式:主要解决对象的组成结构和类之间的关系。
- 行为型模式:主要解决对象之间的交互、职责分配和行为变化问题。
按使用频率划分
设计模式【常用】
1. 单例模式 (Singleton)
- 用途:确保一个类只有一个实例,并提供一个全局访问点。
- 应用场景:数据库连接池、日志管理器、线程池、配置管理等场景中需要全局共享的资源。
- 常见度:非常常见,尤其在需要管理全局状态或系统资源时。
2. 工厂方法模式 (Factory Method) 和 简单工厂 (Simple Factory)
- 用途:定义一个创建对象的接口,让子类决定要实例化的类。
- 应用场景:当系统中存在多种类的对象时,通过工厂方法模式来创建对象,使代码解耦。
- 常见度:非常常见,用于实例化可能变化的类。
3. 策略模式 (Strategy)
- 用途:定义一系列算法,将它们封装起来,并使它们可以互相替换。
- 应用场景:实现不同的业务逻辑或算法,比如支付方式的选择、日志记录方式的不同策略等。
- 常见度:常见,尤其在需要在运行时动态选择算法或逻辑时使用。
4. 观察者模式 (Observer)
- 用途:当对象状态发生变化时,自动通知并更新依赖的对象。
- 应用场景:事件驱动系统、UI组件的状态联动、MVC架构中的视图更新等。
- 常见度:非常常见,特别在订阅/发布模式中。
5. 装饰器模式 (Decorator)
- 用途:动态地为对象添加额外的职责,而不影响其他对象。
- 应用场景:为对象添加功能,比如为文件输入流/输出流添加加密功能、数据校验等。
- 常见度:在需要扩展对象功能时非常常见,尤其是在流式处理和中间件的构建中。
6. 模板方法模式 (Template Method)
- 用途:在父类中定义算法的骨架,子类可以覆盖某些步骤。
- 应用场景:处理具有一致流程的业务逻辑,但其中某些步骤是可变的,比如订单处理、数据处理等。
- 常见度:常见,尤其在具有类似业务流程的场景中。
7. 代理模式 (Proxy)
- 用途:为其他对象提供一种代理,以控制对这个对象的访问。
- 应用场景:远程代理(如RMI)、虚拟代理(如懒加载)、保护代理(如访问控制)。
- 常见度:常见,尤其在需要控制对对象访问的场景中,比如远程方法调用或权限控制。
8. 责任链模式 (Chain of Responsibility)
- 用途:为请求创建一条处理链,每个对象沿链判断是否需要处理该请求。
- 应用场景:事件处理链、审批流程、日志处理(不同级别的日志处理器链)。
- 常见度:常见,尤其在多级处理系统或审批流程中。
9. 建造者模式 (Builder)
- 用途:分步骤构造一个复杂对象,而不依赖于其他对象的内部表示。
- 应用场景:构建复杂对象,如创建具有多参数的对象、SQL查询、构建UI界面等,避免构造器或工厂方法带来的大量参数,使代码更简洁。
- 适用场景:当需要分步骤构造对象且构造过程复杂时,如创建带有多个可选参数的对象或当初始化需要多步设置时(例如SQL查询构建器、HTTP请求构建器)。
- 常见度:常见,尤其在对象属性较多且构造过程较复杂时。
- 使用频率:在构造复杂对象时非常常见,尤其在构造过程需要分步骤并且有多个可选参数的场景下。Java中的
StringBuilder
、StringBuffer
类和HttpRequest.Builder
就是典型的生成器模式应用。
10. 外观模式 (Facade)
- 用途:为一组复杂的子系统提供一个简单的接口,简化客户端对这些子系统的访问。
- 应用场景:为复杂的系统(如服务层)提供统一接口,如数据库操作、Web服务接口等。
- 常见度:较为常见,特别是当需要简化系统接口时。
总结
- 最常见的设计模式:单例模式、工厂模式、策略模式和观察者模式,通常在日常开发和常规业务逻辑实现中最常用。
- 场景驱动的模式:装饰器、模板方法、代理模式和责任链模式,主要在特定业务或需求时使用。
设计模式【不常用】
1. 抽象工厂模式 (Abstract Factory)
- 用途:提供一个创建一系列相关或依赖对象的接口,而无需指定具体类。
- 应用场景:跨平台应用开发(如GUI库的跨平台支持)、生产不同风格的一组产品(如不同品牌的UI控件)。
- 适用场景:在需要创建一组相关联的对象时使用,比如前端组件库的不同主题下的一系列组件。
2. 享元模式 (Flyweight)
- 用途:通过共享减少大量细粒度对象带来的内存开销。
- 应用场景:文字处理系统中的字符对象、地图应用中的图标对象、缓存系统等。
- 适用场景:在系统中有大量相似对象时使用,以减少内存使用,如大量重复数据的游戏对象或界面元素。
3. 中介者模式 (Mediator)
- 用途:用一个中介对象封装一系列对象交互,避免对象之间的直接引用,解耦系统。
- 应用场景:聊天系统、MVC架构中的控制器、UI组件的事件处理。
- 适用场景:当系统中存在大量对象之间的复杂通信时,通过中介者简化交互逻辑。
4. 命令模式 (Command)
- 用途:将请求封装为对象,使得用户可以用不同请求来参数化对象,支持撤销和重做操作。
- 应用场景:事务操作(如数据库操作的撤销与恢复)、任务调度系统、菜单命令。
- 适用场景:在系统中需要执行请求队列、记录操作日志或支持撤销/重做功能时使用。
5. 备忘录模式 (Memento)
- 用途:在不破坏封装的前提下,捕获并存储对象的内部状态,以便之后恢复。
- 应用场景:数据恢复功能(如编辑器的撤销操作)、游戏存档功能。
- 适用场景:在需要记录对象状态以便稍后恢复时使用,比如文本编辑器的多步撤销功能。
6. 状态模式 (State)
- 用途:允许对象在内部状态改变时改变其行为。
- 应用场景:状态驱动的系统(如工单流程的状态转移)、状态机、游戏角色状态(如攻击、防御、逃跑)。
- 适用场景:在对象的行为随状态变化时使用,比如订单状态流转系统或工作流系统。
7. 原型模式 (Prototype)
- 用途:通过克隆现有对象来创建新对象,而不依赖于具体类。
- 应用场景:需要频繁创建对象但对象初始化成本高时、对象结构较复杂。
- 适用场景:在对象初始化成本较高,且希望通过复制已有对象来提高性能时使用,比如拷贝一张复杂数据结构的文档。
8. 桥接模式 (Bridge)
- 用途:将抽象部分与实现部分分离,使它们可以独立变化。
- 应用场景:图形绘制系统中的不同形状和渲染方式、文件转换系统。
- 适用场景:当需要跨多个维度扩展时使用,比如支持多种数据库和多种缓存策略的系统。
9. 组合模式 (Composite)
- 用途:将对象组合成树形结构以表示“部分-整体”的层次结构。
- 应用场景:文件系统、GUI界面(如树状菜单和控件)、组织结构。
- 适用场景:在需要处理树形结构或递归结构的系统中使用,比如图形界面中的复合控件。
10. 访问者模式 (Visitor)
- 用途:为对象结构增加新的操作,而无需更改对象结构本身。
- 应用场景:编译器中的语法树操作、对象序列化与反序列化。
- 适用场景:在需要对对象结构添加新操作但不希望更改对象结构时使用。
11. 解释器模式 (Interpreter)
- 用途:给定一个语言,定义它的语法表示,并实现一个解释器来解释语法。
- 应用场景:SQL解析、表达式求值、规则引擎、脚本解释器。
- 适用场景:在需要解释和执行自定义语言或表达式的场景中使用,比如规则引擎和数学表达式解析器。
总结
较少使用的设计模式通常解决的是较特殊或复杂的需求。例如:
- 享元模式和组合模式多用于性能优化或树结构管理。
- 访问者模式和解释器模式用于需要扩展操作或语言解析的系统。
- 状态模式和中介者模式在实现状态机或复杂的对象通信时非常实用。
设计模式【补充】
1. 迭代器模式 (Iterator)
- 用途:提供一种方法顺序访问一个聚合对象中的各个元素,而不暴露该对象的内部表示。
- 应用场景:遍历容器(如列表、集合、树形结构)中的元素。
- 适用场景:当需要在不同的数据结构上实现一致的访问方式时使用。例如,实现自定义集合类时,可通过迭代器模式为集合提供一致的遍历方式。
- 使用频率:非常高,尤其在Java、C#等语言中,该模式被集合框架广泛使用。
for-each
循环和各种Iterator
接口本质上都实现了迭代器模式。
23种设计模式
https://superlovelace.top/2024/11/08/23种设计模式/