本文是【GoF设计模式】系列的总览篇,可以快速了解23种经典设计模式的分类、意图、核心思想、适用场景。如果想深入学习某一模式,可关注本系列种的详细文章。

什么是设计模式
设计模式是软件开发中被反复验证过的、针对特定问题的通用解决方案。1994年,Erich Gamma、Richard Helm、Ralph Johnson 和 John Vlissides 在《设计模式:可复用面向对象软件的基础》中系统总结了23种经典模式,被称为 GoF 设计模式(Gang of Four)。
这23种模式按目的分为三大类:
- 创建型模式(5种):关注对象的创建方式,让创建过程更灵活
- 结构型模式(7种):关注类和对象的组合方式,让结构更合理
- 行为型模式(11种):关注对象之间的通信和职责分配,让行为更可复用
23种模式的全景层级关系如下:
GoF 设计模式(23种)
├── 创建型(5种)── 对象创建
│ ├── 单例模式
│ ├── 工厂方法模式
│ ├── 抽象工厂模式
│ ├── 建造者模式
│ └── 原型模式
├── 结构型(7种)── 类与对象组合
│ ├── 适配器模式
│ ├── 桥接模式
│ ├── 组合模式
│ ├── 装饰模式
│ ├── 外观模式
│ ├── 享元模式
│ └── 代理模式
└── 行为型(11种)── 对象通信与职责分配├── 责任链模式├── 命令模式├── 解释器模式├── 迭代器模式├── 中介者模式├── 备忘录模式├── 观察者模式├── 状态模式├── 策略模式├── 模板方法模式└── 访问者模式
⚠️ 理解模式的关键不是记住结构,而是理解"为什么要这样做"。而理解"为什么"的基石,是设计原则。
为什么要用设计模式
不用设计模式代码也能跑,但需求一旦增长,"面条代码"很快就会暴露问题:职责堆在一起、强依赖具体实现、改一处崩三处、没法单独测试。设计模式的真正价值不是让代码"好看",而是管理复杂度:
- 复用经验:前人踩过的坑、验证过的结构,直接拿来用,不必从零摸索
- 统一语言:团队说"这里用工厂方法",所有人都知道意图,降低沟通成本
- 隔离变化:把变化的部分封装起来,新增需求时改一个类而不是改一万个地方
- 可测试性:依赖抽象而非具体类,Mock 依赖就能单独测试
💡 设计模式不消灭复杂度,复杂度是问题本身固有的。模式做的是把复杂度管理在可控范围内,让它集中在该集中的地方。
接口还是抽象类
几乎所有设计模式的结构里都有一个"抽象层",有时用接口定义,有时用抽象类定义。选择依据很直接:
| 对比维度 | 接口 | 抽象类 |
|---|---|---|
| 能否有实现 | 只能定义行为契约(Java 8 后可有默认方法) | 可以有完整的字段和方法实现 |
| 适用场景 | 多个不相关类实现同一行为 | 有共享代码、存在 IS-A 继承关系 |
| 典型模式 | 策略、命令、迭代器、观察者、状态 | 模板方法、建造者 |
一句话判断:需要共享代码用抽象类,只定义行为契约用接口。Java 8 之后接口有了默认方法,两者界限变模糊,但核心判断标准不变。
模式不是一成不变的
设计模式是经验的总结,不是教条。理解了意图之后,应该灵活变通:
- 模式可以组合使用:实际项目中很少只用一个模式。责任链的每个节点可以用策略决定如何处理、工厂可以创建装饰后的对象、观察者通知的事件可以用命令封装
- 结构可以简化:教科书里的完整结构有四个角色,但如果你的场景只需要两个,就只写两个。不必为了"模式完整性"硬凑类
- 角色可以合并:抽象工厂和具体工厂可以合并成简单工厂;指挥者和建造者可以合并;中介者可以同时是同事
- 不要为了模式而模式:如果直接
new就能解决问题,就不需要工厂;如果if-else只有两三个分支,就不需要策略。模式是解决痛点的工具,不是目的
⚠️ 真正理解一个模式的标志是:知道什么时候不用它。
设计模式六大原则
每个 GoF 模式背后都对应着一条或多条设计原则,原则是模式"为什么这样设计"的理论依据。理解这六条原则,能在遇到问题时快速定位该用哪个模式。
| 原则 | 核心要义 | 一句话理解 |
|---|---|---|
| 开闭原则(OCP) | 对扩展开放,对修改关闭 | 加功能靠新增类,不改老代码 |
| 里氏代换原则(LSP) | 子类型必须能替换父类型 | 用子类替换父类,程序行为不变 |
| 依赖倒转原则(DIP) | 依赖抽象,不依赖细节 | 高层和低层都依赖接口 |
| 接口隔离原则(ISP) | 不依赖不需要的接口 | 接口拆小,客户端只拿需要的 |
| 迪米特法则(LoD) | 只与直接朋友通信 | 别跟陌生人说话,减少耦合 |
| 合成复用原则(CARP) | 优先用组合,少用继承 | HAS-A 比 IS-A 更灵活 |
创建型模式
创建型模式的核心主题是将对象的创建与使用分离,使系统不直接依赖具体类,而是依赖抽象。
单例模式
意图:保证一个类只有一个实例,并提供全局访问点。
核心思想:通过私有化构造函数,将实例化权收归类自身;对外提供静态方法获取唯一实例。适用于配置管理器、数据库连接池、线程池等全局只需一个实例的场景。
核心角色:唯一实例 + 静态获取方法
适用场景:全局只需一个实例(配置中心、连接池、日志器)
避免场景:不要为图方便把所有工具类都做成单例,会隐藏依赖、难以测试
核心代码:
// 单例模式:私有构造 + 静态获取唯一实例
public class Singleton {private static Singleton instance;private Singleton() {}public static Singleton getInstance() {if (instance == null) {instance = new Singleton();}return instance;}
}
工厂方法模式
意图:定义创建对象的接口,但将实际创建推迟到子类。
核心思想:使用抽象方法替代直接 new,让子类决定实例化哪个具体类。工厂方法使产品类的创建对使用者透明,新增产品只需添加新的子类,无需修改原有代码。
核心角色:抽象工厂 + 具体工厂 + 抽象产品 + 具体产品
适用场景:创建对象需要逻辑判断、未来可能扩展新产品类型
避免场景:产品类型固定且极少变化时直接 new 即可,不必过度设计
核心代码:
// 工厂方法:抽象工厂定义创建接口,子类决定具体产品
interface Product {void use();
}
class ConcreteProduct implements Product {public void use() { }
}
abstract class Factory {abstract Product create();
}
class ConcreteFactory extends Factory {Product create() { return new ConcreteProduct(); }
}
抽象工厂模式
意图:提供创建一系列相关或相互依赖对象的接口,无需指定具体类。
核心思想:在工厂方法基础上进一步抽象,一次管理多个产品族的创建。工厂接口定义了一组创建方法,每个方法负责创建同一产品族中的一个对象。
核心角色:抽象工厂 + 具体工厂 + 产品族
适用场景:需要创建一族相关产品(如跨数据库的 DAO 工厂、跨 UI 风格的组件族)
避免场景:只有单一产品类型时用工厂方法即可,不要套抽象工厂
核心代码:
// 抽象工厂:一组创建方法管理整个产品族
interface GUIFactory {Button createButton();TextField createTextField();
}
class WindowsFactory implements GUIFactory {public Button createButton() { return new WindowsButton(); }public TextField createTextField() { return new WindowsTextField(); }
}
建造者模式
意图:将复杂对象的构建与它的表示分离,使同样的构建过程可以创建不同的表示。
核心思想:使用建造者按步骤组装复杂对象,指挥者控制构建流程,不同的建造者产生不同的产品表示。适用于构造参数繁多、组装步骤复杂的对象。
核心角色:抽象建造者 + 具体建造者 + 指挥者 + 产品
适用场景:参数多、需分步构造、有可选参数的对象(SQL 语句、配置对象、HTTP 请求)
避免场景:参数少且固定的简单对象直接用构造函数,不要为 Builder 而 Builder
核心代码:
// 建造者:分步组装复杂对象,链式调用
class Computer {String cpu;String ram;static class Builder {private Computer computer = new Computer();Builder setCpu(String cpu) { computer.cpu = cpu; return this; }Builder setRam(String ram) { computer.ram = ram; return this; }Computer build() { return computer; }}
}
原型模式
意图:通过复制现有实例来创建新对象,而不是通过构造函数。
核心思想:实现可克隆接口,通过 clone() 方法从原型对象复制出新对象,避免重复执行昂贵的构造过程。特别适用于创建成本高的对象。
核心角色:原型接口 + 具体原型 + 客户端
适用场景:创建成本高(需查库、计算)且需创建多个相似对象
避免场景:对象嵌套深且需深拷贝时慎用,clone() 默认是浅拷贝
核心代码:
// 原型模式:通过克隆现有对象创建新对象
class Prototype implements Cloneable {String name;protected Prototype clone() {Prototype p = new Prototype();p.name = this.name;return p;}
}
结构型模式
结构型模式关注如何将类和对象组合成更大、更灵活的结构,同时保持结构的高效性和可控性。
适配器模式
意图:将一个类的接口转换为客户端期望的另一个接口,使原本接口不兼容的类可以一起工作。
核心思想:类似电源适配器,在两个不兼容接口之间加一层转换。通过继承或组合,将旧接口"翻译"成新接口。
核心角色:目标接口 + 适配器 + 被适配者
适用场景:复用已有类但接口不兼容(旧系统改造、第三方库接入)
避免场景:新系统从零开发时不如直接设计统一接口,适配器是"亡羊补牢"
核心代码:
// 适配器:把不兼容接口转换成目标接口
interface Target {void request();
}
class Adaptee {void specificRequest() { }
}
class Adapter implements Target {private Adaptee adaptee = new Adaptee();public void request() { adaptee.specificRequest(); }
}
桥接模式
意图:将抽象部分与它的实现部分分离,使它们可以独立地变化。
核心思想:通过组合代替继承,把抽象和实现放在两个独立的类层次中。这样可以在运行时动态绑定实现,避免多层继承导致的类爆炸。
核心角色:抽象类 + 实现接口 + 扩充抽象类 + 具体实现
适用场景:一个类存在两个独立变化的维度(形状×颜色、消息类型×发送渠道)
避免场景:只有一个变化维度时不需要,直接继承更简单
核心代码:
// 桥接:抽象持有实现接口,两个维度独立变化
interface Color {void apply();
}
class Red implements Color {public void apply() { }
}
abstract class Shape {protected Color color;abstract void draw();
}
class Circle extends Shape {void draw() { color.apply(); }
}
组合模式
意图:将对象组合成树形结构以表示"部分-整体"的层次结构,使客户端对单个对象和组合对象的使用具有一致性。
核心思想:用统一的接口处理叶子节点和容器节点。容器节点持有子节点(可以是叶子也可以是容器),客户端无需区分单个对象和组合对象。
核心角色:抽象组件 + 叶子节点 + 容器节点
适用场景:树形层次结构且需统一处理节点(文件系统、组织架构、UI 组件树)
避免场景:不是树形结构时无意义
核心代码:
// 组合:叶子与容器统一接口,递归处理树形结构
interface Component {void operation();
}
class Leaf implements Component {public void operation() { }
}
class Composite implements Component {List<Component> children = new ArrayList<>();public void operation() { children.forEach(Component::operation); }
}
装饰模式
意图:动态地给对象添加新的功能,而不改变其结构,提供比继承更灵活的替代方案。
核心思想:用包装对象逐层叠加功能,每层装饰器在调用原方法前后增强行为。功能组合在运行时完成,新增功能只需增加新的装饰器。
核心角色:抽象组件 + 具体组件 + 装饰器基类 + 具体装饰器
适用场景:需要运行时动态叠加功能(I/O 流包装、权限叠加、日志增强)
避免场景:功能固定且单一时直接写在类里即可,多层装饰会降低可读性
核心代码:
// 装饰:包装原对象,调用前后增强功能
interface Coffee {int cost();
}
class SimpleCoffee implements Coffee {public int cost() { return 10; }
}
class MilkDecorator implements Coffee {private Coffee coffee;public int cost() { return coffee.cost() + 3; }
}
外观模式
意图:为子系统中的多个接口提供一个统一的高层接口,使子系统更容易使用。
核心思想:通过一个外观类将复杂子系统的内部细节隐藏起来,客户端只需调用外观类的简单方法,不需要了解底层实现。本质是降低接口的复杂度。
核心角色:外观类 + 子系统类
适用场景:子系统复杂、想为常用操作提供简化入口
避免场景:子系统简单或客户端需要细粒度控制时,外观层反而多余
核心代码:
// 外观:一个入口类简化多个子系统的调用
class CPU {void start() { }
}
class Memory {void load() { }
}
class ComputerFacade {private CPU cpu = new CPU();private Memory memory = new Memory();void start() { cpu.start(); memory.load(); }
}
享元模式
意图:运用共享技术来有效支持大量细粒度的对象。
核心思想:将对象的状态分为内部状态(可共享)和外部状态(由调用方传入),共享内部状态相同的对象,减少内存占用。适用于存在大量相似对象的场景。
核心角色:享元接口 + 具体享元 + 享元工厂
适用场景:存在大量相同或相似对象,内存压力大
避免场景:对象数量少或内部状态不重复时无收益,线程安全需额外处理
核心代码:
// 享元:共享内部状态相同的对象
class Flyweight {String intrinsic; // 内部状态,可共享void operation(String extrinsic) { } // 外部状态由调用方传入
}
class FlyweightFactory {Map<String, Flyweight> pool = new HashMap<>();Flyweight get(String key) {return pool.computeIfAbsent(key, Flyweight::new);}
}
代理模式
意图:为其他对象提供一种代理以控制对这个对象的访问。
核心思想:代理对象持有真实对象的引用,在访问真实对象前后执行额外逻辑(如权限校验、延迟加载、远程调用等)。客户端不知道也不关心自己在操作代理还是真实对象。
核心角色:抽象主题 + 真实主题 + 代理
适用场景:需要在访问前后加控制(权限、延迟加载、远程调用、日志监控)
避免场景:代理逻辑简单到可以直接写在目标类里时,别加一层代理
核心代码:
// 代理:控制对真实对象的访问
interface Subject {void request();
}
class RealSubject implements Subject {public void request() { }
}
class Proxy implements Subject {private RealSubject real;public void request() {if (real == null) { real = new RealSubject(); }real.request(); // 可在前后加权限校验、日志}
}
行为型模式
行为型模式关注对象之间的通信方式以及职责的分配,让对象间的交互更灵活、可扩展。
责任链模式
意图:使多个对象都有机会处理请求,将请求沿处理链传递,直到有对象处理它为止。
核心思想:每个节点持有一个后继节点的引用,请求到达时,如果不能处理就传给下一个节点。解耦了请求发送者和处理者,新增处理器只需插入链中即可。
核心角色:抽象处理器 + 具体处理器 + 客户端
适用场景:多个处理器按顺序处理同一请求(审批流程、过滤器、校验链)
避免场景:处理逻辑确定且单一时直接调用即可,链太长影响性能
核心代码:
// 责任链:不能处理就传给下一个节点
abstract class Handler {protected Handler next;Handler setNext(Handler next) { this.next = next; return next; }abstract void handle(String request);
}
class ConcreteHandler extends Handler {void handle(String request) {if (canHandle(request)) { /* 处理 */ }else if (next != null) { next.handle(request); }}boolean canHandle(String request) { return false; }
}
命令模式
意图:将请求封装为对象,从而可以用不同的请求对客户进行参数化。
核心思想:将"调用哪个方法、传入什么参数"封装成命令对象,支持请求排队、撤销/重做、日志记录等操作。调用者和执行者通过命令对象解耦。
核心角色:命令接口 + 具体命令 + 调用者 + 接收者
适用场景:需要撤销/重做、排队执行、日志记录的场景(编辑器、事务、任务队列)
避免场景:简单的一次性方法调用不需要封装成命令,徒增类数量
核心代码:
// 命令:把请求封装成对象,支持排队和撤销
interface Command {void execute();
}
class Light {void on() { }
}
class LightOnCommand implements Command {private Light light;public void execute() { light.on(); }
}
class Invoker {private Command command;void setCommand(Command cmd) { command = cmd; }void call() { command.execute(); }
}
解释器模式
意图:为语言创建解释器,定义语法的表示并实现其解释逻辑。
核心思想:为简单语言或表达式定义文法规则,每个规则对应一个类,通过递归方式构建抽象语法树并解释执行。适用于规则引擎、脚本引擎等场景。
核心角色:抽象表达式 + 终结符表达式 + 非终结符表达式 + 上下文
适用场景:有规则可定义的简单语言或表达式(规则引擎、SQL 解析、配置表达式)
避免场景:复杂语法用现成解析器框架,不要自己造解释器
核心代码:
// 解释器:为表达式定义解释逻辑,递归构建语法树
interface Expression {boolean interpret(String context);
}
class TerminalExpression implements Expression {private String data;public boolean interpret(String context) { return context.contains(data); }
}
class AndExpression implements Expression {private Expression expr1, expr2;public boolean interpret(String context) {return expr1.interpret(context) && expr2.interpret(context);}
}
迭代器模式
意图:提供一种方法顺序访问聚合对象中的各元素,而不暴露该对象的内部表示。
核心思想:将遍历逻辑从集合中抽出,封装到独立的迭代器对象中。无论底层是数组、链表还是树,对客户端都提供统一的 hasNext()、next() 接口。
核心角色:迭代器接口 + 具体迭代器 + 聚合接口 + 具体聚合
适用场景:需要统一遍历不同结构的集合,或多种遍历方式
避免场景:集合结构简单且只遍历一次,迭代器层多余
核心代码:
// 迭代器:统一遍历接口,不暴露集合内部结构
interface Iterator {boolean hasNext();Object next();
}
class ListAggregate {private Object[] items;public Iterator iterator() {return new Iterator() {int index = 0;public boolean hasNext() { return index < items.length; }public Object next() { return items[index++]; }};}
}
中介者模式
意图:用一个中介对象来封装一系列的对象交互,使各对象不需要显式地相互引用。
核心思想:所有相关对象通过中介者来通信,而不是直接引用彼此。把多对多的网状依赖简化为以中介者为中心的一对多星形结构,降低各组件之间的耦合。
核心角色:抽象中介者 + 具体中介者 + 抽象同事 + 具体同事
适用场景:多个对象之间存在复杂的网状交互(聊天室、UI 组件联动、飞机调度)
避免场景:对象间交互简单、数量少时反而增加复杂度,中介者可能变成上帝类
核心代码:
// 中介者:同事之间通过中介通信,互不直接引用
abstract class Mediator {abstract void relay(Colleague sender, String msg);
}
abstract class Colleague {protected Mediator mediator;void send(String msg) { mediator.relay(this, msg); }abstract void receive(String msg);
}
备忘录模式
意图:在不破坏封装性的前提下,捕获和保存对象的内部状态,以便之后恢复。
核心思想:通过备忘录对象记录原发器的状态快照,管理者负责保存备忘录,需要时可以恢复到之前的某个状态。常用于撤销操作和历史记录。
核心角色:原发器 + 备忘录 + 管理者
适用场景:需要保存和恢复对象历史状态(撤销、快照、事务回滚)
避免场景:状态占用内存大或不需要回溯时,频繁快照耗资源
核心代码:
// 备忘录:保存对象状态快照,需要时恢复
class Memento {private String state;Memento(String state) { this.state = state; }String getState() { return state; }
}
class Originator {private String state;Memento save() { return new Memento(state); }void restore(Memento m) { state = m.getState(); }
}
观察者模式
意图:定义对象间的一对多依赖关系,当一个对象状态改变时,所有依赖者都会自动收到通知。
核心思想:主题维护一个观察者列表,状态变化时通知所有观察者。支持广播通信,新增观察者只需注册,无需修改主题代码。
核心角色:抽象主题 + 具体主题 + 抽象观察者 + 具体观察者
适用场景:一个对象变化需通知多个对象(事件驱动、消息广播、数据绑定)
避免场景:只有一对一依赖或通知频率极高时注意性能,观察者持有引用易致内存泄漏
核心代码:
// 观察者:主题状态变化时通知所有注册的观察者
interface Observer {void update(String event);
}
class Subject {private List<Observer> observers = new ArrayList<>();void attach(Observer o) { observers.add(o); }void notifyAll(String event) {observers.forEach(o -> o.update(event));}
}
状态模式
意图:允许对象在内部状态改变时改变其行为,看起来就像改变了它的类。
核心思想:将每种状态封装为独立的类,状态转换委托给新状态对象处理。消除大量的条件判断,新增状态时只需增加类,不需要修改原有逻辑。
核心角色:状态接口 + 具体状态 + 上下文
适用场景:对象行为随状态变化且状态多、条件分支复杂(订单状态机、审批流程)
避免场景:状态少且转换逻辑简单时 if-else 更清晰,不要过度设计
核心代码:
// 状态:不同状态封装为独立类,状态改变则行为改变
interface State {void handle(Context ctx);
}
class ConcreteStateA implements State {public void handle(Context ctx) { ctx.setState(new ConcreteStateB()); }
}
class Context {private State state;void setState(State s) { state = s; }void request() { state.handle(this); }
}
策略模式
意图:定义一系列算法,把它们封装起来并使它们可以互相替换。
核心思想:将算法的选择和使用分离,每个算法封装在独立的策略类中,客户端持有策略接口,运行时动态选择具体策略。消除了硬编码的条件分支。
核心角色:策略接口 + 具体策略 + 上下文
适用场景:多种算法需要运行时切换(支付方式、折扣策略、排序规则)
避免场景:算法只有两三种且永远不变,if-else 就行,策略类反而臃肿
核心代码:
// 策略:算法封装为独立类,运行时动态替换
interface Strategy {int calculate(int a, int b);
}
class AddStrategy implements Strategy {public int calculate(int a, int b) { return a + b; }
}
class Context {private Strategy strategy;void setStrategy(Strategy s) { strategy = s; }int execute(int a, int b) { return strategy.calculate(a, b); }
}
模板方法模式
意图:在父类中定义算法的骨架,将具体步骤延迟到子类实现。
核心思想:不变的行为在父类用具体方法实现,可变的行为用抽象方法留给子类。这样保证了算法流程的一致性,同时允许子类灵活扩展具体步骤。
核心角色:抽象类 + 具体子类
适用场景:算法流程固定但个别步骤可变(生命周期回调、框架扩展点)
避免场景:流程本身就不固定时用策略更合适;子类过多时继承耦合大
核心代码:
// 模板方法:父类定义算法骨架,子类实现可变步骤
abstract class AbstractClass {public final void templateMethod() {step1();step2();}void step1() { } // 不变步骤,父类实现abstract void step2(); // 可变步骤,子类实现
}
访问者模式
意图:在不修改元素类的前提下,为对象结构中的元素定义新操作。
核心思想:利用双重分派,把操作逻辑封装到访问者中,元素只需调用访问者的方法并把自己传过去。这样可以在不修改现有类的情况下增加新操作,符合开闭原则。
核心角色:访问者接口 + 具体访问者 + 元素接口 + 具体元素
适用场景:稳定对象结构上频繁新增操作(编译器 AST、文档导出、报表生成)
避免场景:对象结构本身也频繁变化时,元素和访问者双重修改成本高
核心代码:
// 访问者:操作逻辑封装到访问者,元素 accept 时双重分派
interface Visitor {void visit(ElementA a);void visit(ElementB b);
}
interface Element {void accept(Visitor v);
}
class ElementA implements Element {public void accept(Visitor v) { v.visit(this); }
}
易混淆模式速查
以下几组模式结构相似、容易搞混,区分它们的关键是看意图而非代码结构。
| 对比组 | 核心区别 | 一句话区分 |
|---|---|---|
| 策略 vs 状态 | 策略是客户端主动选算法;状态是对象内部自动切换 | 策略由外部决定"用哪个",状态由内部决定"变哪个" |
| 装饰 vs 代理 | 装饰强调"增强功能";代理强调"控制访问" | 装饰关心"加什么功能",代理关心"让不让访问" |
| 工厂方法 vs 抽象工厂 | 工厂方法造一个产品;抽象工厂造一族产品 | 一个 create() vs 一组 createA() + createB() |
| 适配器 vs 外观 | 适配器转换接口让两个类协作;外观简化子系统入口 | 适配器是"一对一转换",外观是"一对多简化" |
| 桥接 vs 策略 | 桥接分离两个独立变化的维度;策略只切换算法 | 桥接"双维度组合",策略"单维度替换" |
| 命令 vs 策略 | 命令封装请求支持撤销排队;策略封装算法可互换 | 命令有"执行/撤销"生命周期,策略只"算一次" |
⚠️ 装饰和代理的代码结构几乎完全一样(都是包装类持有被包装对象的引用),区别全在意图:装饰是"加功能",代理是"管访问"。
总览表
| 模式 | 核心意图 | 核心角色 | 典型场景 | JDK/Spring 实例 | 易混淆 |
|---|---|---|---|---|---|
| 单例 | 保证全局唯一实例 | 唯一实例 + 静态方法 | 全局配置、连接池 | Spring Bean、Runtime |
- |
| 工厂方法 | 将创建延迟到子类 | 抽象工厂 + 具体工厂 + 产品 | 创建逻辑需封装 | SLF4J LoggerFactory |
抽象工厂 |
| 抽象工厂 | 创建一族相关产品 | 抽象工厂 + 具体工厂 + 产品族 | 跨库 DAO、跨主题 UI | Connection |
工厂方法 |
| 建造者 | 分步构建复杂对象 | 建造者 + 指挥者 + 产品 | 多参数对象构造 | StringBuilder、Lombok |
- |
| 原型 | 通过复制创建对象 | 原型接口 + 具体原型 | 创建成本高的对象 | Object.clone() |
- |
| 适配器 | 转换不兼容接口 | 目标接口 + 适配器 + 被适配者 | 旧系统改造、第三方接入 | InputStreamReader |
外观 |
| 桥接 | 分离两个变化维度 | 抽象 + 实现接口 + 具体实现 | 双维度变化 | JDBC DriverManager |
策略 |
| 组合 | 统一处理树形结构 | 抽象组件 + 叶子 + 容器 | 文件树、UI 组件树 | Swing JComponent |
- |
| 装饰 | 动态叠加职责 | 抽象组件 + 装饰器基类 | I/O 包装、功能增强 | BufferedInputStream |
代理 |
| 外观 | 简化子系统入口 | 外观类 + 子系统类 | 简化复杂调用 | SLF4J、JdbcTemplate |
适配器 |
| 享元 | 共享对象省内存 | 享元 + 享元工厂 | 大量相似对象 | Integer.valueOf() |
单例 |
| 代理 | 控制对象访问 | 抽象主题 + 真实主题 + 代理 | 权限、延迟加载、AOP | Spring AOP | 装饰 |
| 责任链 | 沿链传递请求 | 抽象处理器 + 具体处理器 | 审批、过滤器 | Servlet Filter |
- |
| 命令 | 封装请求为对象 | 命令 + 调用者 + 接收者 | 撤销、排队、日志 | Runnable |
策略 |
| 解释器 | 定义语法解释器 | 抽象表达式 + 上下文 | 规则引擎、表达式 | Spring SpEL | - |
| 迭代器 | 统一遍历聚合 | 迭代器 + 聚合接口 | 遍历不同结构 | Iterator |
- |
| 中介者 | 集中管理交互 | 中介者 + 同事类 | 网状交互解耦 | DispatcherServlet |
外观 |
| 备忘录 | 保存恢复状态 | 原发器 + 备忘录 + 管理者 | 撤销、快照、存档 | Serializable |
- |
| 观察者 | 状态变化广播 | 主题 + 观察者 | 事件驱动、消息广播 | ApplicationEvent |
- |
| 状态 | 随状态切换行为 | 状态接口 + 具体状态 + 上下文 | 状态机、订单流转 | Spring StateMachine |
策略 |
| 策略 | 封装可互换算法 | 策略接口 + 具体策略 + 上下文 | 支付方式、折扣规则 | Comparator |
状态 |
| 模板方法 | 定义算法骨架 | 抽象类 + 具体子类 | 框架扩展点、回调 | JdbcTemplate |
策略 |
| 访问者 | 为结构新增操作 | 访问者 + 元素 | 编译器 AST、导出 | ASM 字节码 | - |
