设计模式(Design Pattern)是软件开发中针对常见问题的经典解决方案,由 GoF(Gang of Four)在《设计模式:可复用面向对象软件的基础》一书中归纳为23 种模式,分为三大类:创建型模式、结构型模式和行为型模式。以下是它们的分类、区别和作用详解:
一、创建型模式(Creational Patterns)
核心作用:封装对象的创建逻辑,分离对象的创建和使用,使系统更灵活地创建不同类型的对象。
包含模式:
-
工厂方法模式(Factory Method)
- 作用:定义一个创建对象的接口,由子类决定实例化哪个具体类。
- 区别:将简单工厂的静态创建逻辑改为动态(通过子类实现),符合开闭原则。
- 场景:创建对象的逻辑需要延迟到子类实现时(如日志工厂、数据库连接工厂)。
-
抽象工厂模式(Abstract Factory)
- 作用:创建一组相关或依赖的对象(如跨平台 UI 组件:按钮、文本框的组合)。
- 区别:比工厂方法更复杂,用于创建多个产品族(如同时创建 Windows 和 Mac 的 UI 组件)。
-
单例模式(Singleton)
- 作用:确保一个类只有一个实例,并提供全局访问点(如线程池、日志管理器)。
- 区别:通过私有化构造函数、静态实例和线程安全机制实现。
-
原型模式(Prototype)
- 作用:通过复制现有对象创建新对象,避免重复初始化逻辑(如配置对象克隆)。
- 区别:基于对象克隆(实现
Cloneable
接口),适用于创建成本较高的对象。
-
建造者模式(Builder)
- 作用:将复杂对象的构建过程分解为多个步骤,允许不同的构建顺序(如创建用户对象:姓名、年龄、地址分步设置)。
- 区别:分离对象的构建和表示,适合参数多且组合复杂的对象。
二、结构型模式(Structural Patterns)
核心作用:简化对象间的结构关系,优化类或对象的组合方式,提高系统的灵活性和可维护性。
包含模式:
-
适配器模式(Adapter)
- 作用:将一个类的接口转换为另一个接口,使不兼容的类可以协同工作(如电源适配器转换电压)。
- 区别:分为类适配器(继承)和对象适配器(组合),后者更常用。
-
装饰器模式(Decorator)
- 作用:动态地给对象添加新功能,避免继承导致的类爆炸(如咖啡饮品添加调料:牛奶、糖浆)。
- 区别:通过组合方式扩展功能,比继承更灵活(开闭原则)。
-
代理模式(Proxy)
- 作用:为其他对象提供一个代理或占位符,控制对原对象的访问(如远程代理、缓存代理、权限代理)。
- 区别:代理对象与原对象实现相同接口,客户端透明调用。
-
外观模式(Facade)
- 作用:为复杂子系统提供一个统一的接口,简化客户端调用(如整合支付系统的统一入口)。
- 区别:降低客户端与子系统的耦合,属于结构型模式中的 “简化接口” 模式。
-
桥接模式(Bridge)
- 作用:将抽象部分与实现部分分离,使它们可以独立变化(如将 “消息类型” 与 “发送方式” 解耦)。
- 区别:通过组合而非继承实现抽象和实现的分离,适用于多维度变化的场景。
-
组合模式(Composite)
- 作用:将对象组合成树形结构,表示 “部分 - 整体” 的层次关系(如文件系统:文件夹包含文件和子文件夹)。
- 区别:统一处理单个对象(叶子节点)和组合对象(容器节点),简化层次操作。
-
享元模式(Flyweight)
- 作用:共享多个对象的公共状态,减少内存占用(如文本编辑器中的字符共享字体、颜色等公共属性)。
- 区别:通过分离 “内部状态”(共享)和 “外部状态”(不共享)优化性能。
三、行为型模式(Behavioral Patterns)
核心作用:关注对象间的通信和算法设计,优化对象之间的交互流程,提升系统的灵活性和可扩展性。
包含模式:
-
策略模式(Strategy)
- 作用:定义一系列算法,将每个算法封装起来,使它们可以相互替换(如电商促销策略:满减、折扣、赠品)。
- 区别:通过接口实现算法族,运行时动态切换策略,避免多重条件判断。
-
模板方法模式(Template Method)
- 作用:在抽象类中定义算法骨架,具体步骤由子类实现(如 HTTP 请求处理模板:预处理→处理→后处理)。
- 区别:通过继承强制子类实现某些步骤,属于 “顶层设计” 模式。
-
观察者模式(Observer)
- 作用:定义对象间的一对多依赖关系,当一个对象状态改变时,所有依赖者自动更新(如订阅 - 发布系统、股市行情通知)。
- 区别:通过注册 / 注销机制解耦主题(Subject)和观察者(Observer)。
-
迭代器模式(Iterator)
- 作用:提供一种遍历集合元素的统一方式,无需暴露集合内部结构(如 Java 的
Iterator
接口)。 - 区别:分离集合的遍历逻辑,支持不同的遍历方式(正向、反向、跳跃遍历)。
- 作用:提供一种遍历集合元素的统一方式,无需暴露集合内部结构(如 Java 的
-
责任链模式(Chain of Responsibility)
- 作用:将请求的发送者和处理者解耦,请求沿着链传递,直到有一个处理者处理(如审批流程:组长→经理→总监)。
- 区别:避免请求发送者与具体处理者耦合,动态调整链的顺序。
-
命令模式(Command)
- 作用:将 “请求” 封装为对象,使请求发送者和接收者解耦(如撤销操作、日志记录、线程池任务)。
- 区别:通过命令对象(Command)封装动作,支持队列化、撤销等操作。
-
备忘录模式(Memento)
- 作用:在不破坏封装性的前提下,捕获对象的内部状态并保存,以便恢复(如游戏存档、编辑器撤销)。
- 区别:通过备忘录(Memento)对象保存状态,由负责人(Caretaker)管理。
-
状态模式(State)
- 作用:允许对象在内部状态改变时改变行为,对象看起来像是修改了类(如电梯状态:运行、停止、故障)。
- 区别:将状态逻辑封装为独立的状态类,避免大量条件判断。
-
访问者模式(Visitor)
- 作用:将数据结构与作用于结构上的操作解耦,使操作可以独立扩展(如统计文件系统中不同类型文件的大小)。
- 区别:通过访问者(Visitor)类定义操作,数据结构(如元素 Element)负责接待访问者。
-
中介者模式(Mediator)
- 作用:通过中介者对象封装对象间的交互逻辑,避免对象直接引用(如聊天房间中介协调用户消息传递)。
- 区别:减少对象间的直接依赖,将多对多交互转换为一对多(对象与中介者)。
-
解释器模式(Interpreter)
- 作用:给定一种语言,定义其文法的表示,并定义一个解释器来解释语言中的句子(如正则表达式引擎、数学表达式解析)。
- 区别:适用于需要频繁改变文法或解释规则的场景,实现成本较高。
四、三大类模式的核心区别
类型 | 关注重点 | 典型场景 | 关键作用 |
---|---|---|---|
创建型 | 对象的创建方式 | 复杂对象初始化、对象池、单实例 | 解耦对象创建与使用,控制实例化逻辑 |
结构型 | 对象的组合与结构关系 | 接口转换、动态扩展、层次结构 | 优化系统结构,简化对象间的依赖关系 |
行为型 | 对象间的交互与算法设计 | 流程控制、状态管理、消息传递 | 解耦对象交互逻辑,提升系统灵活性 |
五、常见模式:
创建型模式(Creational Patterns)
核心目标:封装对象的创建过程,将对象的创建与使用分离,提高系统的灵活性和可扩展性。
特点:
- 隐藏对象创建的复杂逻辑。
- 通过接口或抽象类定义创建规范,由子类或具体实现决定具体创建方式。
模式名称 | 作用与特点 | 应用场景示例 |
---|---|---|
单例模式(Singleton) | 确保一个类只有一个实例,并提供全局访问点。 | 数据库连接池、配置管理器。 |
工厂模式(Factory Method) | 定义对象创建的接口,子类决定具体实例化哪个类。 | 支付网关(根据支付类型创建不同支付处理器)。 |
抽象工厂模式(Abstract Factory) | 创建相关或依赖对象的家族,无需指定具体类。 | GUI框架(创建跨平台的按钮、文本框等组件)。 |
建造者模式(Builder) | 将复杂对象的构建与其表示分离,逐步构建对象。 | 生成复杂配置文件(如XML、JSON)。 |
原型模式(Prototype) | 通过复制现有对象创建新对象,避免重复初始化。 | 克隆配置对象、快速生成相似数据。 |
结构型模式(Structural Patterns)
核心目标:组合类或对象的结构,形成更大的结构,简化系统设计并提高灵活性。
特点:
- 通过继承、组合或聚合等方式,定义类或对象之间的关系。
- 关注如何高效地组织代码结构,优化系统的可维护性。
常见模式:
模式名称 | 作用与特点 | 应用场景示例 |
---|---|---|
适配器模式(Adapter) | 将不兼容的接口转换为兼容的接口,使原本不兼容的类可以协作。 | 旧系统接口与新系统对接。 |
装饰器模式(Decorator) | 动态地为对象添加额外功能,比继承更灵活。 | 给咖啡加糖、奶泡(动态扩展功能)。 |
代理模式(Proxy) | 为对象提供代理,控制对原始对象的访问(如权限校验、延迟加载)。 | 远程调用、缓存代理。 |
外观模式(Facade) | 为子系统提供统一接口,简化复杂系统的调用。 | 一键启动电脑(调用多个硬件组件)。 |
组合模式(Composite) | 将对象组合成树形结构,表示“部分-整体”的层次关系。 | 文件系统(文件夹包含文件和子文件夹)。 |
行为型模式(Behavioral Patterns)
核心目标:定义对象之间的交互和职责分配,提高对象间的协作效率。
特点:
- 关注对象之间的通信方式(如事件、回调、链式调用)。
- 解耦对象之间的依赖关系,增强系统的可维护性。
模式名称 | 作用与特点 | 应用场景示例 |
---|---|---|
观察者模式(Observer) | 定义对象间的一对多依赖关系,当状态变化时通知所有依赖对象。 | 事件驱动系统(如GUI事件监听)。 |
策略模式(Strategy) | 将算法封装为独立类,允许在运行时动态切换策略。 | 支付系统(支持多种支付方式)。 |
责任链模式(Chain of Responsibility) | 将请求的发送者和接收者解耦,多个对象依次处理请求。 | HTTP请求过滤器链(如权限校验、日志记录)。 |
命令模式(Command) | 将请求封装为对象,支持参数化请求、队列操作和撤销功能。 | 撤销/重做功能(如文本编辑器)。 |
状态模式(State) | 允许对象在内部状态改变时改变行为,避免冗长的条件判断。 | 状态机(如订单状态:待支付、已发货、已完成)。 |
六、总结
设计模式是软件开发的 “最佳实践”,其本质是通过抽象和封装解决特定问题。学习时需注意:
- 理解场景:每种模式都有适用场景,避免为了用模式而用模式。
- 对比差异:如工厂方法与抽象工厂、装饰器与适配器的区别,需结合具体需求选择。
- 结合语言特性:如 Java 的接口、继承、反射等机制会影响模式的实现方式(如单例的线程安全实现)。
通过实际项目练习,逐步掌握不同模式的应用,可以显著提升代码的可维护性、可扩展性和复用性。