当前位置: 首页 > news >正文

Java中 23 种设计模式介绍,附带示例

文章目录

  • 设计模式六大原则
  • 设计模式分类
    • 1、创建型模式(Creational Patterns)
    • 2、结构型模式(Structural Patterns)
    • 3、行为型模式(Behavioral Patterns)
  • 一、创建型模式(Creational Patterns)
    • 1、单例(Singleton)
    • 2、工厂方法(Factory Method)
    • 3、抽象工厂(Abstract Factory)
    • 4、建造者(Builder)
    • 5、原型(Prototype)
  • 二、结构型模式(Structural Patterns)
    • 1、适配器(Adapter)
    • 2、装饰器(Decorator)
    • 3、代理(Proxy)
    • 4、组合(Composite)
    • 5、外观(Facade)
    • 6、桥接(Bridge)
    • 7、享元(Flyweight)
  • 三、行为型模式(Behavioral Patterns)
    • 1、观察者(Observer)
    • 2、策略(Strategy)
    • 3、命令(Command)
    • 4、责任链(Chain of Responsibility)
    • 5、状态(State)
    • 6、模板方法(Template Method)
    • 7、迭代器(Iterator)
    • 8、中介者(Mediator)
    • 9、访问者(Visitor)
    • 10、备忘录模式(Memento)
    • 11、解释器模式(Interpreter)


设计模式六大原则

1、单一职责原则(SRP - Single Responsibility Principle)
  含义:一个类只负责一件事情,不要让多个类承担过多功能。
  作用:降低类的复杂度,提高可读性和可维护性。

2、开放-封闭原则(OCP - Open/Closed Principle)
  含义:对扩展开放、对修改封闭——新需求通过增加代码来实现,而不是去改老代码
  作用:防止改动老功能时引入新 bug,增强系统稳定性。

3、里氏替换原则(LSP - Liskov Substitution Principle)
  含义:子类必须能够替换父类,且程序逻辑不出错。
  作用:保证继承体系的稳定性,让父类的地方都能用子类替代。

4、依赖倒置原则(DIP - Dependency Inversion Principle)
  含义:高层模块不应该依赖低层模块,两者都依赖抽象(接口/抽象类);抽象不依赖具体实现,具体实现依赖抽象。
  作用:减少模块间的耦合,让实现可自由替换。

5、接口隔离原则(ISP - Interface Segregation Principle)
  含义:客户端不应该依赖它不需要的方法,一个接口尽量精简,不要大而全。
  作用:减少实现类的负担,避免实现无用方法。

6、迪米特法则(LOD - Law of Demeter / 最少知道原则)
  含义:一个对象应当对其他对象有尽可能少的了解,减少直接依赖。
  作用:降低耦合性,提高模块的独立性。

设计模式分类

1、创建型模式(Creational Patterns)

作用: 关注对象的创建机制,通过控制对象的实例化过程,提高代码的灵活性和可复用性。

核心目标: 解耦对象的创建与使用,避免硬编码的实例化方式。

常见模式:

  1. 单例(Singleton):确保一个类只有一个实例,并提供全局访问点。
  2. 工厂方法(Factory Method):定义创建对象的接口,由子类决定实例化哪个类。
  3. 抽象工厂(Abstract Factory):创建相关或依赖对象的家族,无需指定具体类。
  4. 建造者(Builder):分步骤构建复杂对象,分离构造与表示。
  5. 原型(Prototype):通过克隆现有对象来创建新对象,避免重复初始化。

应用场景: 需要动态创建对象、隐藏创建逻辑(如依赖注入)、优化资源复用(如数据库连接池)。

2、结构型模式(Structural Patterns)

作用: 关注类和对象的组合方式,形成更大的结构,以解决系统模块间的组织问题。

核心目标: 通过组合(而非继承)实现功能的扩展,提高系统的可维护性。

常见模式:

  1. 适配器(Adapter):转换接口使不兼容的类能协同工作。
  2. 装饰器(Decorator):动态地为对象添加职责,避免子类膨胀。
  3. 代理(Proxy):为其他对象提供代理以控制访问(如远程代理、虚拟代理)。
  4. 组合(Composite):将对象组合成树形结构以表示“部分-整体”层次。
  5. 外观(Facade):为子系统提供统一的简化接口。
  6. 桥接(Bridge):分离抽象与实现,使它们能独立变化。
  7. 享元(Flyweight):共享细粒度对象以减少内存占用(如字符缓存)。

应用场景: 整合第三方库、优化对象结构、简化复杂子系统交互。

3、行为型模式(Behavioral Patterns)

作用: 关注对象间的通信和职责分配,定义系统运行时的工作流程。

核心目标: 解耦对象间的交互,提高代码的可扩展性和可维护性。

常见模式:

  1. 观察者(Observer):定义对象间的一对多依赖,状态变更时自动通知。
  2. 策略(Strategy):封装算法族,使其可互相替换(如排序算法)。
  3. 命令(Command):将请求封装为对象,支持撤销、队列等操作。
  4. 责任链(Chain of Responsibility):将请求沿处理链传递,直到被处理。
  5. 状态(State):允许对象在内部状态改变时改变行为。
  6. 模板方法(Template Method):定义算法骨架,子类重写特定步骤。
  7. 迭代器(Iterator):提供一种方法顺序访问聚合对象的元素。
  8. 中介者(Mediator):集中管理对象间的复杂交互,减少耦合。
  9. 访问者(Visitor):将算法与对象结构分离,便于新增操作。
  10. 备忘录模式(Memento):保存对象的状态,以便后续能恢复到此状态。
  11. 解释器模式(Interpreter):定义一种语言的文法规则,并提供一个解释器来解释该语言中的表达式(如数学公式、SQL查询等)。

应用场景: 实现松耦合的组件交互、动态调整行为(如插件系统)、管理复杂状态流转。

一、创建型模式(Creational Patterns)

1、单例(Singleton)

  单例模式是一种创建型设计模式,用于确保一个类只有一个实例,并提供全局访问点。它常用于管理共享资源(如数据库连接、线程池、配置对象等),避免重复创建实例导致资源浪费或数据不一致。

核心思想:

  1. 限制实例数量为1

  2. 对外暴露同意的访问方法(通常是getInstance()

  3. 构造器私有化,阻止外部 new

  4. 通常要考虑线程安全性能

实现方式:

 (1)饿汉式(线程安全、简单、但可能浪费资源)

public class Singleton {private static final Singleton INSTANCE = new Singleton(); // 类加载时创建实例private Singleton() {} // 私有化构造器public static Singleton getInstance() {return INSTANCE;}
}

 (2) 懒汉式

// 线程不安全
public class Singleton {private static Singleton instance; private Singleton() {}public static Singleton getInstance() { // 线程不安全if (instance == null) { instance = new Singleton();}return instance;}
}// 线程安全
public class Singleton {private static Singleton instance;private Singleton() {}public static synchronized Singleton getInstance() { // 方法加锁if (instance == null) {instance = new Singleton();}return instance;}
}

 (3)双重检查锁(DCL,推荐)

public class Singleton {private static volatile Singleton instance; // volatile 防止指令重排序private Singleton() {}public static Singleton getInstance() {if (instance == null) { // 第一次检查(不加锁)synchronized (Singleton.class) { // 加锁if (instance == null) { // 第二次检查(防止多线程竞争)instance = new Singleton();}}}return instance;}
}

 (4) 静态内部类(最优雅)

public class Singleton {private Singleton() {}private static class Holder {private static final Singleton INSTANCE = new Singleton();}public static Singleton getInstance() {return Holder.INSTANCE;}
}

 (5) 枚举单例

public enum Singleton {INSTANCE; // 唯一实例public void doSomething() {System.out.println("Singleton method");}
}// 使用:
Singleton.INSTANCE.doSomething();

小结

实现方式是否懒加载线程安全性能推荐度
饿汉式★★★
懒汉式(同步方法)
双重检查锁★★★★
静态内部类★★★★★
枚举★★★★★

2、工厂方法(Factory Method)

  工厂方法模式是一种创建型设计模式,它定义了一个用于创建对象的接口,但让子类决定实例化哪个类。工厂方法模式的核心思想是将对象的创建延迟到子类,从而提供更高的灵活性和扩展性。

核心思想:

  1. 定义工厂接口:提供一个创建对象的抽象方法,由子类实现。
  2. 延迟实例化:不直接在父类中创建对象,而是由子类决定如何创建。
  3. 解耦客户端与具体类:客户端只依赖抽象工厂和抽象产品,不依赖具体实现。

结构组成:

  1. 抽象产品(Product):定义产品的公共接口
  2. 具体产品(ConcreteProduct):实现产品接口的具体类
  3. 抽象工厂(Factory):声明创建产品的方法
  4. 具体工厂(ConcreteFactory):实现工厂接口,决定生产哪种具体产品

在这里插入图片描述
实现方式:

 (1)抽象产品

public interface Logger {void log(String message);
}

 (2)具体产品

public class FileLogger implements Logger {@Overridepublic void log(String message) {System.out.println("写入文件日志: " + message);}
}public class DatabaseLogger implements Logger {@Overridepublic void log(String message) {System.out.println("写入数据库日志: " + message);}
}

 (3)抽象工厂

public interface LoggerFactory {Logger createLogger();
}

 (4)具体工厂

public class FileLoggerFactory implements LoggerFactory {@Overridepublic Logger createLogger() {return new FileLogger();}
}public class DatabaseLoggerFactory implements LoggerFactory {@Overridepublic Logger createLogger() {return new DatabaseLogger();}
}

 (5)客户端调用

public class Client {public static void main(String[] args) {LoggerFactory factory = new FileLoggerFactory(); // 或 DatabaseLoggerFactory()Logger logger = factory.createLogger();logger.log("系统启动成功");}
}

优缺点分析
 优点
 ✅ 遵循 开闭原则(新增产品只需新增工厂和产品类)
 ✅ 客户端只依赖抽象(低耦合)
 ✅ 对象创建逻辑集中在工厂,方便维护
 缺点
 ❌ 每新增一种产品,都要写一个具体工厂类(类数量会增加)
 ❌ 代码结构相对复杂,不适合产品种类很少且变化不大的场景

3、抽象工厂(Abstract Factory)

  抽象工厂模式是一种创建型设计模式,它提供一个接口用于创建相关或依赖对象的家族,而无需指定它们的具体类。它比工厂方法模式更高级,适用于需要创建一组相互关联的对象的场景(如 GUI 组件、游戏角色装备等)。

核心思想:

  1. 产品家族:创建一组相关对象(如 Button + TextBox + Menu)。
  2. 抽象接口:客户端只依赖抽象工厂和抽象产品,不依赖具体实现。
  3. 可替换性:切换产品家族只需更换具体工厂(如从 Windows 风格切换到 Mac 风格)。

结构组成:

  1. 抽象工厂接口(AbstractFactory):声明创建一系列产品对象的方法
  2. 具体工厂类(oncreteFactory):实现抽象工厂接口,负责创建特定产品族的对象
  3. 抽象产品接口(AbstractProduct):为每种产品声明接口
  4. 具体产品类(ConcreteProduct):实现抽象产品接口,定义产品的具体功能

在这里插入图片描述
实现方式:

 (1)抽象产品

// 抽象产品:按钮
public interface Button {void render();
}// 抽象产品:文本框
public interface TextField {void show();
}

 (2)具体产品

// Windows 按钮
public class WinButton implements Button {@Overridepublic void render() {System.out.println("渲染 Windows 风格按钮");}
}// Mac 按钮
public class MacButton implements Button {@Overridepublic void render() {System.out.println("渲染 Mac 风格按钮");}
}// Windows 文本框
public class WinTextField implements TextField {@Overridepublic void show() {System.out.println("显示 Windows 风格文本框");}
}// Mac 文本框
public class MacTextField implements TextField {@Overridepublic void show() {System.out.println("显示 Mac 风格文本框");}
}

 (3)抽象工厂

public interface UIFactory {Button createButton();TextField createTextField();
}

 (4)具体工厂

public class WinFactory implements UIFactory {@Overridepublic Button createButton() {return new WinButton();}@Overridepublic TextField createTextField() {return new WinTextField();}
}public class MacFactory implements UIFactory {@Overridepublic Button createButton() {return new MacButton();}@Overridepublic TextField createTextField() {return new MacTextField();}
}

 (5)客户端调用

public class Client {public static void main(String[] args) {UIFactory factory = new WinFactory();Button button = factory.createButton();TextField textField = factory.createTextField();button.render();textField.show();}
}

优缺点分析
 优点
 ✅ 产品族一致性:确保一个工厂创建的产品是同一个产品族,风格统一。
 ✅ 解耦:客户端代码与具体产品类解耦,只依赖抽象接口。
 ✅ 易于切换产品族:更换产品族只需替换工厂类。
 缺点
 ❌ 不易扩展新产品种类:如果需要在已有产品族中增加新产品接口,所有工厂类都要修改。
 ❌ 结构相对复杂,代码量较多

抽象工厂模式 vs 工厂方法模式

对比点抽象工厂模式工厂方法模式
核心目标创建一组相关对象(产品家族)创建单一对象(子类决定实例化)
扩展性扩展产品族容易,扩展产品类型困难扩展新产品容易(新增工厂子类)
适用场景需要整体替换组件(如切换主题)需要灵活创建单一对象

4、建造者(Builder)

  建造者模式是一种创建型设计模式,用于分步骤构建复杂对象,并允许相同的构建过程创建不同的表示。它特别适用于需要灵活构造具有多个组成部分的对象的场景(如配置文件解析、SQL 查询构造、UI 组件生成等)。

核心思想:

  1. 分离构造与表示:将对象的构造过程(Builder)与对象本身(Product)解耦。
  2. 分步构建:通过链式调用逐步设置对象的属性。
  3. 灵活扩展:可以轻松支持新的对象表示(如 HTML 格式 vs Markdown 格式)。

结构组成:

  1. 产品类(Product)
     最终要生成的对象,通常是一个复杂对象
     包含多个组成部分(属性)
  2. 抽象建造者接口(Builder)
     定义创建产品各个部分的抽象方法
     不涉及具体的部件装配细节
  3. 具体建造者(ConcreteBuilder)
     实现 Builder 接口
     具体负责产品部件的装配与组合
  4. 指挥者(Director)
     负责安排构建的顺序
     将产品的构造过程和具体构造细节隔离

示例代码:

 (1)产品类

public class Computer {private String cpu;private String gpu;private String memory;private String storage;public void setCpu(String cpu) { this.cpu = cpu; }public void setGpu(String gpu) { this.gpu = gpu; }public void setMemory(String memory) { this.memory = memory; }public void setStorage(String storage) { this.storage = storage; }@Overridepublic String toString() {return "Computer {cpu='" + cpu + "', gpu='" + gpu + "', memory='" + memory + "', storage='" + storage + "'}";}
}

 (2)抽象建造者

public interface ComputerBuilder {void buildCpu();void buildGpu();void buildMemory();void buildStorage();Computer getResult();
}

 (3)具体建造者

public class GamingComputerBuilder implements ComputerBuilder {private Computer computer = new Computer();@Overridepublic void buildCpu() { computer.setCpu("Intel i9"); }@Overridepublic void buildGpu() { computer.setGpu("NVIDIA RTX 4090"); }@Overridepublic void buildMemory() { computer.setMemory("32GB DDR5"); }@Overridepublic void buildStorage() { computer.setStorage("2TB NVMe SSD"); }@Overridepublic Computer getResult() { return computer; }
}

 (4)指挥者

public class Director {private ComputerBuilder builder;public Director(ComputerBuilder builder) {this.builder = builder;}public Computer construct() {builder.buildCpu();builder.buildGpu();builder.buildMemory();builder.buildStorage();return builder.getResult();}
}

 (5)客户端使用

public class Client {public static void main(String[] args) {ComputerBuilder builder = new GamingComputerBuilder();Director director = new Director(builder);Computer gamingPC = director.construct();System.out.println(gamingPC);}
}

优缺点分析
 优点
 ✅ 将构建与表示分离,解耦
 ✅ 构建过程可复用
 ✅ 代码可读性高,可扩展性强
 ✅ 同一构建过程可生产不同产品
 缺点
 ❌ 如果产品的组成部分变化多,需要新增很多具体建造者类,代码量会增加
 ❌ 适用于简单对象构建(会显得过度设计)

5、原型(Prototype)

  原型模式是一种创建型设计模式,它通过复制现有对象(原型)来创建新对象,而不是通过 new 实例化。这种方式特别适用于创建成本较高需要动态配置的对象,同时支持运行时对象类型复制

核心思想:

  1. 克隆代替 new:通过复制现有对象生成新对象,避免重复初始化。
  2. 动态创建对象:运行时决定克隆哪个对象(如游戏中的敌人复制)。
  3. 减少资源消耗:适用于创建成本高的对象(如数据库连接、复杂配置)。

结构组成:

  1. 原型接口(Prototype):声明 clone() 方法。
  2. 具体原型类(ConcretePrototype):实现 clone() 方法。
  3. 客户端(Client):通过调用原型对象的 clone() 来获得新对象。

实现示例:

 (1)浅拷贝

class Person implements Cloneable {String name;Address address; // 引用类型public Person(String name, Address address) {this.name = name;this.address = address;}@Overrideprotected Person clone() throws CloneNotSupportedException {return (Person) super.clone(); // 浅拷贝}
}class Address {String city;public Address(String city) {this.city = city;}
}public class PrototypeDemo {public static void main(String[] args) throws CloneNotSupportedException {Address addr = new Address("Beijing");Person p1 = new Person("Alice", addr);Person p2 = p1.clone();System.out.println(p1 == p2); // falseSystem.out.println(p1.address == p2.address); // true(引用相同)}
}

 (2)深拷贝

class PersonDeep implements Cloneable {String name;Address address;public PersonDeep(String name, Address address) {this.name = name;this.address = address;}@Overrideprotected PersonDeep clone() throws CloneNotSupportedException {PersonDeep cloned = (PersonDeep) super.clone();cloned.address = new Address(this.address.city); // 手动复制引用对象return cloned;}
}class Address {String city;public Address(String city) {this.city = city;}
}public class PrototypeDeepDemo {public static void main(String[] args) throws CloneNotSupportedException {Address addr = new Address("Beijing");PersonDeep p1 = new PersonDeep("Alice", addr);PersonDeep p2 = p1.clone();System.out.println(p1.address == p2.address); // false(引用不同)}
}

优缺点分析
 优点
 ✅ 通过克隆对象避免重复初始化,大幅提升性能。
 ✅ 动态创建对象,运行时灵活改变类型。
 ✅ 隐藏对象创建的复杂性,客户端无需知道细节。
 缺点
 ❌ 深拷贝实现复杂,尤其是对象引用层级深时。
 ❌ 必须保证被克隆对象支持 clone() 或序列化。
 ❌ 对含有循环引用的对象,深拷贝可能处理困难。

二、结构型模式(Structural Patterns)

1、适配器(Adapter)

  适配器模式是一种结构型设计模式,它允许接口不兼容的类能够协同工作,通过将一个类的接口转换成客户端期望的另一个接口。适配器模式的核心思想是"转换接口,解决兼容性问题",类似于现实中的电源适配器(将220V电压转换为5V供手机充电)。

核心思想:

  1. 接口转换:将一个类的接口转换成客户端期望的接口。
  2. 兼容性桥梁:让原本因接口不匹配而无法一起工作的类能够协同工作。
  3. 解耦:客户端只需依赖目标接口,无需关心具体适配逻辑。

结构组成:

  1. 目标接口(Target):客户端期望的接口(如 USB 接口)。
  2. 被适配者(Adaptee):需要被适配的现有类(如 Lightning 接口)。
  3. 适配器(Adapter):实现目标接口,并内部调用被适配者的方法(如 LightningToUSBAdapter)。

分类:

类型实现方式特点缺点
类适配器(Class Adapter)通过继承(extends)被适配者结构简单Java 单继承限制
对象适配器(Object Adapter)通过组合(持有被适配者实例)灵活,不受单继承限制多一层对象引用
接口适配器(Interface Adapter / Default Adapter)提供一个抽象类实现接口的所有方法为空,子类按需重写适合接口方法很多的情况只适用于接口

实现示例:

 (1)类适配器

// 目标接口
interface Voltage5V {int output5V();
}// 被适配类
class Voltage220V {public int output220V() {System.out.println("输出 220V 电压");return 220;}
}// 适配器类(继承 + 实现接口)
class ClassAdapter extends Voltage220V implements Voltage5V {@Overridepublic int output5V() {int srcV = output220V();int dstV = srcV / 44; // 转换逻辑System.out.println("适配后输出 " + dstV + "V 电压");return dstV;}
}// 测试
public class Main {public static void main(String[] args) {Voltage5V adapter = new ClassAdapter();adapter.output5V();}
}

 (2)对象适配器

// 目标接口
interface Voltage5V {int output5V();
}// 被适配类
class Voltage220V {public int output220V() {System.out.println("输出 220V 电压");return 220;}
}// 适配器类(组合)
class ObjectAdapter implements Voltage5V {private Voltage220V voltage220V;public ObjectAdapter(Voltage220V voltage220V) {this.voltage220V = voltage220V;}@Overridepublic int output5V() {int srcV = voltage220V.output220V();int dstV = srcV / 44;System.out.println("适配后输出 " + dstV + "V 电压");return dstV;}
}// 测试
public class Main {public static void main(String[] args) {Voltage220V v220 = new Voltage220V();Voltage5V adapter = new ObjectAdapter(v220);adapter.output5V();}
}

 (3)接口适配器

**// 大接口(很多方法)
interface MouseListener {void onClick();void onDoubleClick();void onMove();
}// 空实现适配器
abstract class MouseAdapter implements MouseListener {@Override public void onClick() {}@Override public void onDoubleClick() {}@Override public void onMove() {}
}// 客户端只关心 onClick
class MyMouseHandler extends MouseAdapter {@Overridepublic void onClick() {System.out.println("鼠标被点击!");}
}// 测试
public class Main {public static void main(String[] args) {MouseListener listener = new MyMouseHandler();listener.onClick(); // 输出:鼠标被点击!}
}

优缺点分析
 优点
 ✅ 复用已有类:不用修改老类代码就能兼容新接口
 ✅ 符合开闭原则:扩展而不是修改原有类
 ✅ 灵活性高:对象适配器可同时适配多个被适配者
 缺点
 ❌ 增加系统复杂度:多了一层适配类
 ❌ 可能影响性能:额外调用层可能带来微小性能损耗

2、装饰器(Decorator)

  装饰器模式是一种结构型设计模式,它允许动态地向对象添加额外的功能,而无需修改其原始类。装饰器模式通过包装(Wrapping)的方式扩展对象的行为,比继承更加灵活,符合开闭原则(Open-Closed Principle)。

核心思想:

  1. 动态扩展功能:在不修改原有类的情况下,动态地给对象添加新功能。
  2. 替代继承:避免因功能组合导致子类爆炸。
  3. 包装机制:通过嵌套多个装饰器实现功能叠加。

结构组成:

  1. 抽象组件(Component):定义对象接口,规范所有装饰类和具体组件的行为。
  2. 具体组件(ConcreteComponent):实现抽象组件,是被装饰的原始对象。
  3. 抽象装饰类(Decorator):持有 Component 引用,实现 Component 接口,并将请求转发给被装饰对象。
  4. 具体装饰类(ConcreteDecorator):在调用原有方法前后,增加新的功能。

在这里插入图片描述

实现示例:

 (1)抽象组件

// Component
public interface Coffee {String getDescription();double cost();
}

 (2)具体组件

// ConcreteComponent
public class SimpleCoffee implements Coffee {@Overridepublic String getDescription() {return "普通咖啡";}@Overridepublic double cost() {return 5.0;}
}

 (3)抽象装饰类

// Decorator
public abstract class CoffeeDecorator implements Coffee {protected Coffee decoratedCoffee; // 被装饰的对象public CoffeeDecorator(Coffee coffee) {this.decoratedCoffee = coffee;}@Overridepublic String getDescription() {return decoratedCoffee.getDescription();}@Overridepublic double cost() {return decoratedCoffee.cost();}
}

 (4)具体装饰类

// ConcreteDecoratorA
public class MilkDecorator extends CoffeeDecorator {public MilkDecorator(Coffee coffee) {super(coffee);}@Overridepublic String getDescription() {return super.getDescription() + " + 牛奶";}@Overridepublic double cost() {return super.cost() + 2.0;}
}// ConcreteDecoratorB
public class SugarDecorator extends CoffeeDecorator {public SugarDecorator(Coffee coffee) {super(coffee);}@Overridepublic String getDescription() {return super.getDescription() + " + 糖";}@Overridepublic double cost() {return super.cost() + 1.0;}
}

 (5)使用

public class Main {public static void main(String[] args) {Coffee coffee = new SimpleCoffee();System.out.println(coffee.getDescription() + " 价格: " + coffee.cost());coffee = new MilkDecorator(coffee); // 加牛奶coffee = new SugarDecorator(coffee); // 再加糖System.out.println(coffee.getDescription() + " 价格: " + coffee.cost());}
}

优缺点分析
 优点
 ✅ 动态扩展功能,无需修改原有类。
 ✅ 符合开闭原则(对扩展开放,对修改关闭)。
 ✅ 替代继承,更灵活。
 缺点
 ❌ 多层装饰时代码较复杂。
 ❌ 设计不当可能导致大量小类。

3、代理(Proxy)

  代理模式是一种结构型设计模式,它通过创建一个代理对象来控制对另一个对象的访问。代理模式的核心思想是"间接访问",即在客户端和目标对象之间插入一个中间层(代理),用于增强功能控制访问

核心思想:

  1. 间接访问:客户端不直接操作目标对象,而是通过代理对象间接访问。
  2. 功能增强:代理可以在调用目标对象前后添加额外逻辑(如日志、缓存、权限检查)。
  3. 访问控制:代理可以限制对目标对象的访问(如延迟加载、防火墙)。

结构组成:

  1. 抽象主题(Subject):定义目标对象和代理对象的公共接口(如 Database)。
  2. 真实主题(RealSubject):实际执行业务逻辑的目标对象(如 RealDatabase)。
  3. 代理(Proxy):实现抽象主题,控制对真实主题的访问(如 DatabaseProxy)。

在这里插入图片描述

常见实现:

 (1)静态代理
    优点:直观,类型安全;缺点:类爆炸、维护成本高。

// 抽象主题
public interface OrderService {void placeOrder(String sku, int qty);
}// 真实对象
public class OrderServiceImpl implements OrderService {public void placeOrder(String sku, int qty) {System.out.println("下单成功: " + sku + " x" + qty);}
}// 代理对象(手写)
public class OrderServiceProxy implements OrderService {private final OrderService target;public OrderServiceProxy(OrderService target) { this.target = target; }@Overridepublic void placeOrder(String sku, int qty) {long t1 = System.currentTimeMillis();try {System.out.println("[LOG] 入参校验...");target.placeOrder(sku, qty);                 // 转发调用System.out.println("[METRIC] 成功计数+1");} catch (RuntimeException e) {System.out.println("[METRIC] 失败计数+1");throw e;} finally {System.out.println("[TIME] cost=" + (System.currentTimeMillis()-t1)+"ms");}}
}

 (2)JDK 动态代理(基于接口)
    优点:无需为每个类写代理;缺点:要求有接口

import java.lang.reflect.*;public class JdkProxy {@SuppressWarnings("unchecked")public static <T> T wrap(T target) {Class<?>[] ifaces = target.getClass().getInterfaces();return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(),ifaces,(proxy, method, args) -> {// 前置System.out.println("[Before] " + method.getName());Object ret = method.invoke(target, args); // 调用真实对象// 后置System.out.println("[After] " + method.getName());return ret;});}
}

 (3)CGLIB 代理(基于继承/子类)
    优点:没接口也能代理;缺点:不能代理 final 类/方法。`

// 依赖:cglib
import net.sf.cglib.proxy.*;public class CglibProxy implements MethodInterceptor {private final Object target;public CglibProxy(Object target) { this.target = target; }public Object create() {Enhancer e = new Enhancer();e.setSuperclass(target.getClass());e.setCallback(this);return e.create(); // 生成子类}@Overridepublic Object intercept(Object obj, java.lang.reflect.Method m, Object[] a, MethodProxy mp) throws Throwable {System.out.println("[Before] " + m.getName());Object ret = mp.invoke(target, a); // 调用被代理实例System.out.println("[After] " + m.getName());return ret;}
}

优缺点分析
 优点
 ✅ 职责清晰:代理对象专注于控制访问,目标对象专注于业务逻辑。
 ✅ 高扩展性:无需修改目标对象即可增强功能。
 ✅ 安全性:通过代理隐藏真实对象细节。
 缺点
 ❌ 可能引入性能开销(如远程代理的网络延迟)。
 ❌ 代码复杂度增加(需维护代理类)。

小结:

核心思想: 通过代理对象间接访问目标对象,实现功能增强或访问控制。

常见代理类型:

   1. 虚拟代理(延迟加载)。
   2. 保护代理(权限控制)。
   3. 远程代理(RPC 调用)。
   4. 缓存代理(结果缓存)。

实现方式:

   1. 静态代理(手动编写代理类)。
   2. 动态代理(运行时生成,如 JDK 动态代理)。

适用场景:

   1. 远程对象访问(如 RPCRMI)。
   2. 延迟加载(如大型文件、图片的按需加载)。
   3. 访问控制(如权限校验、防火墙)。
   4. 日志记录和监控(如记录方法调用耗时)。
   5. 缓存(如数据库查询结果缓存)。

4、组合(Composite)

   组合模式是一种结构型设计模式,它允许你将对象组合成树形结构来表示“部分-整体”的层次关系,并让客户端以统一的方式处理单个对象和组合对象。

核心思想:

  1. 树形结构:表示“部分-整体”的层次关系(如文件系统、公司组织架构)。
  2. 统一操作:客户端无需区分处理叶子节点(单个对象)和容器节点(组合对象)。
  3. 递归组合:容器节点可以包含其他容器或叶子节点,形成递归结构。

结构组成:

  1. 抽象组件(Component):
     定义组合中对象的通用接口(如 add()remove()display())。
     既可以代表叶子,也可以代表组合。
  2. 叶子节点(Leaf):
     没有子节点的最终对象。
     实现 Component 接口,但 add() / remove() 通常是空实现或抛异常。
  3. 组合节点(Composite):
     持有子节点(List<Component>)。
     实现 add() / remove() 等方法,并在 display() 中递归调用子节点的方法。
  4. 客户端(Client):
     通过 Component 接口与对象交互,不需要知道对象是叶子还是组合。

实现示例:

 (1)定义组件接口

// 抽象组件
public interface FileSystemComponent {void display(String indent); // 显示文件或目录结构long getSize();             // 计算大小
}

 (2)定义叶子节点(文件)

public class File implements FileSystemComponent {private String name;private long size;public File(String name, long size) {this.name = name;this.size = size;}@Overridepublic void display(String indent) {System.out.println(indent + "📄 " + name + " (" + size + " bytes)");}@Overridepublic long getSize() {return size;}
}

 (3)定义容器节点(目录)

public class Directory implements FileSystemComponent {private String name;private List<FileSystemComponent> children = new ArrayList<>();public Directory(String name) {this.name = name;}// 添加子组件(文件或目录)public void add(FileSystemComponent component) {children.add(component);}// 移除子组件public void remove(FileSystemComponent component) {children.remove(component);}@Overridepublic void display(String indent) {System.out.println(indent + "📁 " + name);for (FileSystemComponent child : children) {child.display(indent + "    "); // 递归显示子节点}}@Overridepublic long getSize() {long totalSize = 0;for (FileSystemComponent child : children) {totalSize += child.getSize(); // 递归计算子节点大小}return totalSize;}
}

 (4)客户端使用

public class Client {public static void main(String[] args) {// 创建文件File file1 = new File("document.txt", 1024);File file2 = new File("image.jpg", 2048);// 创建子目录Directory subDir = new Directory("Subfolder");subDir.add(new File("note.txt", 512));// 创建根目录Directory rootDir = new Directory("Root");rootDir.add(file1);rootDir.add(file2);rootDir.add(subDir);// 显示整个文件系统rootDir.display("");// 计算总大小System.out.println("Total size: " + rootDir.getSize() + " bytes");}
}

优缺点分析
 优点
 ✅ 统一处理:客户端无需区分叶子节点和容器节点。
 ✅ 灵活扩展:支持动态添加新类型的组件。
 ✅ 符合开闭原则:新增组件无需修改现有代码。
 缺点
 ❌ 设计复杂:需递归处理子节点。
 ❌ 类型检查困难:需在运行时检查组件类型(如 instanceof)。

5、外观(Facade)

  外观模式是一种结构型设计模式,它通过提供一个统一的简化接口,来隐藏子系统的复杂性,使客户端更容易使用系统功能。外观模式的核心思想是"提供一站式服务",类似于酒店的前台(客户只需与前台交互,无需直接联系保洁、餐饮、客房等多个部门)。

核心思想:

  1. 简化接口:外部只需要面对一个统一入口,而不需要自己去和多个复杂类交互。
  2. 解耦客户端与子系统:客户端只需与外观交互,无需了解子系统内部细节。
  3. 降低使用成本:减少客户端对多个子系统的直接依赖。

结构组成:

  1. 外观类(Facade):提供简化的高层接口,内部协调多个子系统。
  2. 子系统(Subsystems):实现具体功能的多个类或模块(外观会调用它们)。
  3. 客户端(Client):通过外观接口与系统交互,不直接接触子系统。

示例代码:

 (1)子系统

// DVD播放器
public class DVDPlayer {public void on() { System.out.println("DVD播放器开启"); }public void play(String movie) { System.out.println("播放电影: " + movie); }public void off() { System.out.println("DVD播放器关闭"); }
}// 投影仪
public class Projector {public void on() { System.out.println("投影仪开启"); }public void setInput(String source) { System.out.println("投影仪输入源: " + source); }public void off() { System.out.println("投影仪关闭"); }
}// 音响系统
public class SoundSystem {public void on() { System.out.println("音响系统开启"); }public void setVolume(int level) { System.out.println("音量设置为: " + level); }public void off() { System.out.println("音响系统关闭"); }
}// 灯光控制
public class LightControl {public void dim(int brightness) { System.out.println("灯光调暗至: " + brightness + "%"); }public void on() { System.out.println("灯光开启"); }public void off() { System.out.println("灯光关闭"); }
}

 (2)定义外观类

public class HomeTheaterFacade {private DVDPlayer dvdPlayer;private Projector projector;private SoundSystem soundSystem;private LightControl lightControl;public HomeTheaterFacade() {this.dvdPlayer = new DVDPlayer();this.projector = new Projector();this.soundSystem = new SoundSystem();this.lightControl = new LightControl();}// 提供一键观影方法public void watchMovie(String movie) {System.out.println("准备播放电影...");lightControl.dim(30);          // 调暗灯光projector.on();                // 打开投影仪projector.setInput("DVD");     // 设置输入源soundSystem.on();              // 打开音响soundSystem.setVolume(70);     // 设置音量dvdPlayer.on();               // 打开DVDdvdPlayer.play(movie);        // 播放电影}// 提供一键关闭方法public void endMovie() {System.out.println("关闭家庭影院...");dvdPlayer.off();soundSystem.off();projector.off();lightControl.on();}
}

 (3)客户端使用

public class Client {public static void main(String[] args) {HomeTheaterFacade facade = new HomeTheaterFacade();// 一键观影(无需操作多个子系统)facade.watchMovie("星际穿越");// 一键关闭facade.endMovie();}
}

优缺点分析
 优点
 ✅ 简化使用:客户端只需调用一个入口,操作简单。
 ✅ 降低耦合:子系统的变化不会直接影响客户端。
 ✅ 更安全:隐藏了系统内部的复杂性。
 缺点
 ❌ 过度封装:可能会让外观类变成“上帝类”,承担过多逻辑。
 ❌ 不适合频繁变化的系统:如果子系统接口经常变化,外观类也要频繁修改。

6、桥接(Bridge)

  桥接模式是一种结构型设计模式,它将抽象部分实现部分分离,使它们可以独立变化。桥接模式的核心思想是"用组合代替继承",通过将抽象和实现解耦,避免因多层继承导致的类爆炸问题。

核心思想:

  1. 分离抽象与实现:抽象层(如遥控器)和实现层(如电视品牌)独立变化。
  2. 组合优于继承:通过组合关系连接抽象和实现,而非多层继承。
  3. 动态绑定:运行时决定抽象与实现的组合方式。

结构组成:

  1. 抽象类(Abstraction):定义抽象接口,并持有实现层的引用(如 RemoteControl)。
  2. 扩展抽象类(RefinedAbstraction):对抽象化的扩展(如 AdvancedRemoteControl)。
  3. 实现接口(Implementor):定义实现层的接口。
  4. 具体实现类(ConcreteImplementor):实现Implementor接口的具体逻辑。

在这里插入图片描述

示例代码:

 (1)定义实现化接口(电视品牌)

// 实现化接口:电视
public interface TV {void on();void off();void tuneChannel(int channel);
}

 (2)定义具体实现化(不同品牌的电视)

// Sony电视实现
public class SonyTV implements TV {@Overridepublic void on() {System.out.println("Sony TV is ON");}@Overridepublic void off() {System.out.println("Sony TV is OFF");}@Overridepublic void tuneChannel(int channel) {System.out.println("Sony TV tuned to channel " + channel);}
}// Samsung电视实现
public class SamsungTV implements TV {@Overridepublic void on() {System.out.println("Samsung TV is ON");}@Overridepublic void off() {System.out.println("Samsung TV is OFF");}@Overridepublic void tuneChannel(int channel) {System.out.println("Samsung TV tuned to channel " + channel);}
}

 (3)定义抽象化(遥控器基类)

// 抽象化:遥控器
public abstract class RemoteControl {protected TV tv; // 持有实现层的引用public RemoteControl(TV tv) {this.tv = tv;}public abstract void turnOn();public abstract void turnOff();public abstract void setChannel(int channel);
}

 (4)定义扩展抽象化(高级遥控器)

// 扩展抽象化:高级遥控器
public class AdvancedRemoteControl extends RemoteControl {public AdvancedRemoteControl(TV tv) {super(tv);}public void mute() {System.out.println("TV muted");}@Overridepublic void turnOn() {tv.on();}@Overridepublic void turnOff() {tv.off();}@Overridepublic void setChannel(int channel) {tv.tuneChannel(channel);}
}

 (5)客户端使用

public class Client {public static void main(String[] args) {// 创建具体电视TV sonyTV = new SonyTV();TV samsungTV = new SamsungTV();// 基础遥控器控制Sony电视RemoteControl basicRemote = new RemoteControl(sonyTV) {@Overridepublic void turnOn() { tv.on(); }@Overridepublic void turnOff() { tv.off(); }@Overridepublic void setChannel(int channel) { tv.tuneChannel(channel); }};basicRemote.turnOn();          // 输出:Sony TV is ONbasicRemote.setChannel(5);     // 输出:Sony TV tuned to channel 5// 高级遥控器控制Samsung电视AdvancedRemoteControl advancedRemote = new AdvancedRemoteControl(samsungTV);advancedRemote.turnOn();       // 输出:Samsung TV is ONadvancedRemote.mute();         // 输出:TV muted}
}

应用场景:

  1. 需要多维度扩展(如遥控器类型 × 电视品牌)。
  2. 避免多层继承(如形状×颜色、操作系统×文件格式)。
  3. 运行时切换实现(如动态更换数据库驱动)。

优缺点分析
 优点
 ✅ 抽象与实现分离,互不影响。
 ✅ 扩展灵活,可以独立增加新的抽象类和实现类。
 ✅ 避免继承导致的类爆炸问题。
 缺点
 ❌ 增加系统复杂度(需设计抽象层和实现层)。
 ❌ 对高内聚的简单系统可能过度设计。

7、享元(Flyweight)

  享元模式是一种结构型设计模式,它通过共享对象来减少内存使用,特别适用于处理大量相似对象的场景。享元模式的核心思想是"共享细粒度对象",将对象的内部状态(Intrinsic)和外部状态(Extrinsic)分离,通过共享内部状态来节省资源。

核心思想:

  1. 抽象类(Abstraction):定义抽象接口,并持有实现层的引用(如 RemoteControl)。
  2. 状态分离:
     内部状态(Intrinsic):对象中不变的、可共享的部分(如字符、图标)。
     外部状态(Extrinsic):对象中变化的、不可共享的部分(如位置、颜色)。
  3. 减少内存占用:适用于存在大量相似对象的系统(如游戏中的粒子、文档中的字符)。

结构组成:

  1. 享元工厂(FlyweightFactory):创建并管理享元对象,确保合理共享。
  2. 享元接口(Flyweight):定义享元对象的接口,通常包含操作外部状态的方法。
  3. 具体享元(ConcreteFlyweight):实现享元接口,存储内部状态。
  4. 非共享享元(UnsharedFlyweight):不需要共享的对象(可选)。
  5. 客户端(Client):维护外部状态,并通过享元工厂获取享元对象。

在这里插入图片描述

示例代码:

 (1)定义享元接口

public interface Character {void display(String color, int x, int y); // 外部状态:颜色、位置
}

 (2)定义具体享元(字符对象)

public class ConcreteCharacter implements Character {private char symbol;  // 内部状态(共享)private String font;  // 内部状态(共享)private int size;     // 内部状态(共享)public ConcreteCharacter(char symbol, String font, int size) {this.symbol = symbol;this.font = font;this.size = size;}@Overridepublic void display(String color, int x, int y) {System.out.printf("Symbol: %c, Font: %s, Size: %d, Color: %s, Position: (%d, %d)\n",symbol, font, size, color, x, y);}
}

 (3)定义享元工厂

import java.util.HashMap;
import java.util.Map;public class CharacterFactory {private Map<String, Character> characters = new HashMap<>();// 获取或创建字符享元public Character getCharacter(char symbol, String font, int size) {String key = symbol + font + size; // 唯一标识内部状态if (!characters.containsKey(key)) {characters.put(key, new ConcreteCharacter(symbol, font, size));}return characters.get(key);}// 获取已创建的享元数量public int getTotalCharacters() {return characters.size();}
}

 (4)客户端使用

public class Client {public static void main(String[] args) {CharacterFactory factory = new CharacterFactory();// 文本 "HELLO" 的字符和位置String text = "HELLO";int[][] positions = {{0, 0}, {1, 0}, {2, 0}, {3, 0}, {4, 0}};String[] colors = {"Red", "Green", "Blue", "Yellow", "Black"};// 显示文本(共享字体和大小,独立颜色和位置)for (int i = 0; i < text.length(); i++) {Character character = factory.getCharacter(text.charAt(i), "Arial", 12);character.display(colors[i], positions[i][0], positions[i][1]);}System.out.println("Total unique characters created: " + factory.getTotalCharacters());}
}

应用场景:

  1. 系统中存在大量相似对象(如游戏中的子弹、棋子)。
  2. 对象的大部分状态可以外部化(如字符的位置、颜色)。
  3. 需要缓存或池化对象(如线程池、数据库连接池)。

优缺点分析
 优点
 ✅ 幅减少内存使用,提高性能。
 ✅ 降低对象创建的频率,减少 GC 压力。
 ✅ 内部状态集中管理,更易维护。
 缺点
 ❌ 增加了系统复杂度,需要区分内部状态与外部状态。
 ❌ 外部状态的管理由客户端负责,可能会增加使用难度。
 ❌ 如果外部状态很多,传递成本可能变高。

三、行为型模式(Behavioral Patterns)

1、观察者(Observer)

  观察者模式是一种行为型设计模式,它定义了对象之间的一种一对多依赖关系,当一个对象(被观察者)的状态发生改变时,所有依赖它的对象(观察者)都会自动收到通知并更新。观察者模式的核心思想是"发布-订阅"机制,广泛用于事件处理系统、GUI组件和数据监听等场景。

核心思想:

  1. 解耦:被观察者(Subject)和观察者(Observer)之间松耦合。
  2. 动态订阅:观察者可以随时注册或取消订阅被观察者。
  3. 自动通知:被观察者状态变化时,自动通知所有观察者。

组成结构:

  1. 被观察者(Subject):维护观察者列表,提供注册、注销和通知方法(如 NewsAgency)。
  2. 具体被观察者(ConcreteSubject):实现被观察者接口,存储状态并触发通知(如 WeatherStation)。
  3. 观察者(Observer):定义更新接口(如 Subscriber)。
  4. 具体观察者(ConcreteObserver):实现观察者接口,完成具体的更新逻辑(如 EmailSubscriber)。

两种通知风格:

  1. 推(Push):Subject 把变化数据直接推给 Observer(参数更明确,耦合略紧)。
  2. 拉(Pull):Subject 只发“变了”的信号,Observer 再回头拉取所需数据(更通用、耦合更低)。

通知时机:

  1. 同步:简单直观,但一次更新里若观察者很多可能卡顿。
  2. 异步:用线程池/消息队列,提升解耦与吞吐,但要考虑顺序、重试、背压等。

代码示例:

 (1)定义观察者接口

public interface Observer<T> {         // 观察者void update(T event, Subject<T> subject); // 推: 用 event; 拉: 通过 subject 获取
}

 (2)定义被观察者接口

public interface Subject<T> {          // 被观察者void register(Observer<T> o);void unregister(Observer<T> o);void notifyObservers(T event);     // 推/拉共用入口
}

 (3)被观察者实现(用 CopyOnWriteArrayList 便于并发读)

import java.util.concurrent.CopyOnWriteArrayList;
import java.util.List;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;public class PriceBoard implements Subject<Double> {private final List<Observer<Double>> observers = new CopyOnWriteArrayList<>();private volatile double lastPrice = 0.0;// 可切换同步/异步:传 null 表示同步;给线程池表示异步private final Executor executor;public PriceBoard() { this(null); }public PriceBoard(Executor executor) { this.executor = executor; }@Override public void register(Observer<Double> o)   { observers.add(o); }@Override public void unregister(Observer<Double> o) { observers.remove(o); }public void setPrice(double newPrice) {this.lastPrice = newPrice;notifyObservers(newPrice); // 触发通知}public double getLastPrice() { return lastPrice; }   // 供“拉”模式使用@Overridepublic void notifyObservers(Double event) {for (Observer<Double> o : observers) {Runnable task = () -> {try {o.update(event, this);               // 推: event; 拉: 调 this.getLastPrice()} catch (Exception e) {// 重要:隔离单个观察者的异常,避免影响其它观察者e.printStackTrace();}};if (executor == null) task.run(); else executor.execute(task);}}
}

 (4)观察者(演示推/拉两种写法)

public class PushObserver implements Observer<Double> {@Overridepublic void update(Double event, Subject<Double> subject) {System.out.println("[PUSH] 收到最新价格: " + event);}
}public class PullObserver implements Observer<Double> {@Overridepublic void update(Double event, Subject<Double> subject) {double current = ((PriceBoard) subject).getLastPrice();System.out.println("[PULL] 当前读取价格: " + current);}
}

 (5)使用

public class Demo {public static void main(String[] args) {// 同步通知PriceBoard board = new PriceBoard();board.register(new PushObserver());board.register(new PullObserver());board.setPrice(101.5);// 异步通知(线程池)PriceBoard asyncBoard = new PriceBoard(Executors.newCachedThreadPool());asyncBoard.register(new PushObserver());asyncBoard.setPrice(202.3);}
}

优缺点分析
 优点
 ✅ 解耦:察者和被观察者之间通过抽象接口通信,不需要了解彼此的具体实现,符合 依赖倒置原则。
 ✅ 动态关系:以在运行时动态增加或移除观察者,不需要修改被观察者的代码。
 ✅ 广播通信:一个事件可以被多个观察者同时接收,实现一对多通知机制。
 缺点
 ❌ 通知顺序不确定:如果有多个观察者订阅同一个事件,通知的先后顺序可能不确定,可能影响执行结果。
 ❌ 可能导致循环依赖:如果观察者和被观察者之间存在反向依赖(比如观察者更新后又触发被观察者的状态改变),可能会造成死循环。

与近邻模式去区别:

模式关键目的什么时候用
观察者一对多通知,对象内解耦同进程/同模块内的事件联动
发布-订阅(Pub/Sub)通过中介(Broker)解耦发布者与订阅者,支持跨进程系统/服务级解耦、异步高吞吐
中介者(Mediator)对象间复杂交互集中到中介者里多对象网状交互转为星型结构
责任链顺序传递请求,直到被处理流水线式可拦截处理的请求流

2、策略(Strategy)

  策略模式是一种行为型设计模式。它把一组可互换的算法封装成独立的策略类(或函数),并让它们在运行时互换,从而把算法的选择与使用分离

核心思想:

  1. 定义算法族:将不同的算法封装成独立的策略类。
  2. 动态切换:客户端可以在运行时选择不同的策略。
  3. 解耦:将算法的定义与使用分离,避免条件语句的滥用。

组成结构:

  1. 策略接口(Strategy):定义算法的公共接口(通常是一个方法)。
  2. 具体策略(ConcreteStrategy):实现策略接口的不同算法类。
  3. 上下文(Context):持有一个 Strategy 引用,通过它调用具体策略;可以在运行时替换策略。

代码示例:

 (1)定义策略接口

public interface PaymentStrategy {void pay(double amount); // 支付方法
}

 (2)定义具体策略

// 信用卡支付
public class CreditCardPayment implements PaymentStrategy {private String cardNumber;private String cvv;public CreditCardPayment(String cardNumber, String cvv) {this.cardNumber = cardNumber;this.cvv = cvv;}@Overridepublic void pay(double amount) {System.out.printf("Paid %.2f via Credit Card (%s)\n", amount, cardNumber);}
}// 支付宝支付
public class AlipayPayment implements PaymentStrategy {private String account;public AlipayPayment(String account) {this.account = account;}@Overridepublic void pay(double amount) {System.out.printf("Paid %.2f via Alipay (%s)\n", amount, account);}
}// 微信支付
public class WechatPayment implements PaymentStrategy {private String openId;public WechatPayment(String openId) {this.openId = openId;}@Overridepublic void pay(double amount) {System.out.printf("Paid %.2f via WeChat Pay (%s)\n", amount, openId);}
}

 (3)定义上下文

public class PaymentContext {private PaymentStrategy strategy; // 持有策略对象// 设置支付策略public void setPaymentStrategy(PaymentStrategy strategy) {this.strategy = strategy;}// 执行支付public void executePayment(double amount) {if (strategy == null) {throw new IllegalStateException("Payment strategy not set!");}strategy.pay(amount);}
}

 (4)客户端使用

public class Client {public static void main(String[] args) {PaymentContext context = new PaymentContext();// 使用信用卡支付context.setPaymentStrategy(new CreditCardPayment("1234-5678-9012-3456", "123"));context.executePayment(100.0); // 输出:Paid 100.00 via Credit Card (1234-5678-9012-3456)// 切换为支付宝支付context.setPaymentStrategy(new AlipayPayment("alice@example.com"));context.executePayment(200.0); // 输出:Paid 200.00 via Alipay (alice@example.com)// 切换为微信支付context.setPaymentStrategy(new WechatPayment("wx_123456"));context.executePayment(300.0); // 输出:Paid 300.00 via WeChat Pay (wx_123456)}
}

 (5)使用Lambda实现

// 策略接口(函数式接口)
@FunctionalInterface
public interface PaymentStrategy {void pay(double amount);
}// 上下文(不变)
public class PaymentContext {private PaymentStrategy strategy;public void setStrategy(PaymentStrategy strategy) {this.strategy = strategy;}public void executePayment(double amount) {strategy.pay(amount);}
}// 客户端使用Lambda
PaymentContext context = new PaymentContext();// 直接传递Lambda表达式
context.setStrategy(amount -> System.out.println("CreditCard: " + amount));
context.executePayment(100.0);// 或使用方法引用
context.setStrategy(System.out::println); // 简单场景直接打印
context.executePayment(200.0);

优缺点分析
 优点
 ✅ 遵循单一职责 / 开闭原则:把算法封装到独立类,便于维护和扩展。
 ✅ 消除条件分支:替换 if/elseswitch,逻辑更清晰。
 ✅ 便于单元测试:每个策略单独测试。
 ✅ 运行时灵活切换:可以在运行时选择或替换策略(配置、用户选择、A/B 测试等)。
 缺点
 ❌ 策略类数量可能增多:大量简单策略会产生很多小类(可用 lambda 或枚举减轻)。
 ❌ 策略与上下文的耦合管理:策略需要知道哪些外部状态(外部状态应由 Context 传入)。
 ❌ 选择逻辑仍需集中管理:当策略选择逻辑复杂时,可能需要工厂/注册器,增加架构复杂性。
 ❌ 状态管理:如果策略有可变状态,要注意线程安全(最好无状态或显式并发控制)。

3、命令(Command)

  命令模式是一种行为型设计模式。它把“请求”(动作/操作)封装成一个对象,从而将请求的发起者(Invoker)和执行者(Receiver)解耦,并能把请求当作对象来传递、排队、记录、撤销或持久化。

核心思想:

  1. 请求即对象:将一个操作(方法调用、请求)封装成一个 Command 对象,包含要做什么(execute)以及必要的参数/上下文。
  2. 解耦调用者与执行者:客户端创建命令并把它交给调用者(Invoker)——调用者只知道执行命令,不知道具体实现。
  3. 支持扩展操作:可以轻松添加新命令,而无需修改现有代码。

组成结构:

  1. 命令接口(Command):声明执行操作的接口(如 execute(),常带 undo())。
  2. 具体命令(ConcreteCommand):实现 Command,保存对 Receiver 的引用以及操作所需参数;在 execute() 中调用 Receiver 的方法。
  3. 接收者(Receiver):知道如何实施具体操作(实际业务逻辑)。
  4. 调用者(Invoker):持有命令对象并在某个时刻调用 execute()
  5. 客户端(Client):创建具体命令并设置接收者和调用者。
    在这里插入图片描述

代码示例:

 (1)定义命令接口

public interface Command {void execute();void undo(); // 可选:支持撤销
}

 (2)定义接收者(实际执行操作的对象)

public class TextEditor {private StringBuilder content = new StringBuilder();public void save(String text) {content.append(text);System.out.println("Saved: " + text);}public void deleteLast() {if (content.length() > 0) {String deleted = content.substring(content.length() - 1);content.deleteCharAt(content.length() - 1);System.out.println("Undo: removed '" + deleted + "'");}}public String getContent() {return content.toString();}
}

 (3)定义具体命令

// 保存命令
public class SaveCommand implements Command {private TextEditor receiver;private String text;public SaveCommand(TextEditor receiver, String text) {this.receiver = receiver;this.text = text;}@Overridepublic void execute() {receiver.save(text);}@Overridepublic void undo() {receiver.deleteLast();}
}

 (4)定义调用者(触发命令的对象)

public class MenuItem {private Command command;public void setCommand(Command command) {this.command = command;}public void click() {command.execute();}public void undoClick() {command.undo();}
}

 (5)客户端使用

public class Client {public static void main(String[] args) {// 创建接收者(实际执行操作的对象)TextEditor editor = new TextEditor();// 创建具体命令并绑定接收者Command saveHello = new SaveCommand(editor, "Hello");Command saveWorld = new SaveCommand(editor, " World!");// 创建调用者(如菜单按钮)MenuItem saveButton = new MenuItem();// 执行命令saveButton.setCommand(saveHello);saveButton.click(); // 输出: Saved: HellosaveButton.setCommand(saveWorld);saveButton.click(); // 输出: Saved:  World!System.out.println("Current content: " + editor.getContent()); // 输出: Hello World!// 撤销操作saveButton.undoClick(); // 输出: Undo: removed '!'saveButton.undoClick(); // 输出: Undo: removed ' 'System.out.println("After undo: " + editor.getContent()); // 输出: Hello}
}

优缺点分析
 优点
 ✅ 松耦合:调用者只持有命令接口,与具体执行者解耦。
 ✅ 易扩展:增加新命令无需改变调用者代码。
 ✅ 支持队列、日志、撤销/重做、事务记录、远程调用:因为请求被封装成对象。
 ✅ 合性好:可实现宏命令(批量执行/回滚)。
 缺点
 ❌ 类数量增多:每个具体操作可能对应一个命令类(可用 lambda、通用命令减少)。
 ❌ 设计复杂度提高:为简单需求过度使用会显得臃肿。
 ❌ 状态管理与序列化成本:持久化命令或实现撤销时需要管理额外状态(可能复杂)。

4、责任链(Chain of Responsibility)

  责任链模式是一种 行为型设计模式,它将多个处理器(对象)以链式结构连接在一起,每个处理器都有机会处理请求,如果当前处理器无法处理,就把请求传递给下一个处理器,直到有处理器能处理为止。

核心思想:

  1. 链式处理:请求沿处理链传递,直到被某个处理器处理。
  2. 动态组合:可以灵活地增加或修改处理链。
  3. 解耦:发送者无需知道请求最终由谁处理。

组成结构:

  1. 处理器接口(Handler):定义处理请求的接口(如 handleRequest())。
  2. 具体处理器(ConcreteHandler):实现处理器接口,决定是否处理请求或传递给下一个处理器。
  3. 客户端(Client):初始化处理链并触发请求。

在这里插入图片描述

示例代码:

 (1)定义处理器接口

public abstract class Approver {protected Approver nextApprover; // 下一个处理器public void setNextApprover(Approver nextApprover) {this.nextApprover = nextApprover;}public abstract void handleRequest(int amount); // 处理请求
}

 (2)定义具体处理器

// 经理审批(<= 1000)
public class Manager extends Approver {@Overridepublic void handleRequest(int amount) {if (amount <= 1000) {System.out.println("Manager approves: " + amount);} else if (nextApprover != null) {nextApprover.handleRequest(amount); // 传递给下一级}}
}// 总监审批(<= 5000)
public class Director extends Approver {@Overridepublic void handleRequest(int amount) {if (amount <= 5000) {System.out.println("Director approves: " + amount);} else if (nextApprover != null) {nextApprover.handleRequest(amount);}}
}// CEO审批(> 5000)
public class CEO extends Approver {@Overridepublic void handleRequest(int amount) {System.out.println("CEO approves: " + amount);}
}

 (3)客户端构建处理链并触发请求

public class Client {public static void main(String[] args) {// 构建责任链Approver manager = new Manager();Approver director = new Director();Approver ceo = new CEO();manager.setNextApprover(director);director.setNextApprover(ceo);// 触发请求manager.handleRequest(800);    // Manager approves: 800manager.handleRequest(3000);   // Director approves: 3000manager.handleRequest(10000);  // CEO approves: 10000}
}

优缺点分析
 优点
 ✅ 降低耦合度:请求发送者和接收者解耦,请求可以被不同对象处理。
 ✅ 灵活性高:可以动态调整责任链,新增或修改处理者无需改动客户端代码。
 ✅ 符合开闭原则:扩展处理逻辑时只需新增处理者类。
 缺点
 ❌ 请求可能未被处理:如果没有合适的处理者,可能导致请求丢失(需兜底逻辑)。
 ❌ 调试困难:请求在链上流转,不易追踪,尤其是链较长时。
 ❌ 性能隐患:如果责任链很长,请求需要经过多个处理者,可能影响性能。

5、状态(State)

  状态模式是一种行为型设计模式,它允许一个对象在其内部状态改变时改变其行为,使对象看起来像是修改了它的类。状态模式的核心思想是"将状态抽象为独立的对象,并将行为委托给当前状态对象",从而避免庞大的条件语句并提高可扩展性。

核心思想:

  1. 状态即对象:将每个状态封装成独立的类。
  2. 行为委托:上下文对象(Context)将行为委托给当前状态对象。
  3. 消除条件分支:用多态替代 if-else 或 switch-case 的状态判断。

组成结构:

  1. 上下文(Context):维护当前状态,并将行为委托给状态对象(如 Order)。
  2. 抽象状态类/接口(State):定义状态的公共接口(如 OrderState)。
  3. 具体状态类(ConcreteState):实现状态接口,定义该状态下的行为(如 PendingStateShippedState)。

在这里插入图片描述

代码示例:

 (1)定义状态接口

public interface OrderState {void pay(Order order);       // 支付void ship(Order order);      // 发货void complete(Order order);  // 完成
}

 (2)定义具体状态

// 待支付状态
public class PendingState implements OrderState {@Overridepublic void pay(Order order) {System.out.println("订单支付成功!");order.setState(new PaidState()); // 状态流转}@Overridepublic void ship(Order order) {System.out.println("错误:订单未支付,不能发货!");}@Overridepublic void complete(Order order) {System.out.println("错误:订单未支付,不能完成!");}
}// 已支付状态
public class PaidState implements OrderState {@Overridepublic void pay(Order order) {System.out.println("错误:订单已支付,无需重复支付!");}@Overridepublic void ship(Order order) {System.out.println("订单已发货!");order.setState(new ShippedState()); // 状态流转}@Overridepublic void complete(Order order) {System.out.println("错误:订单未发货,不能完成!");}
}// 已发货状态
public class ShippedState implements OrderState {@Overridepublic void pay(Order order) {System.out.println("错误:订单已支付!");}@Overridepublic void ship(Order order) {System.out.println("错误:订单已发货!");}@Overridepublic void complete(Order order) {System.out.println("订单已完成!");order.setState(new CompletedState()); // 状态流转}
}// 已完成状态(终止状态)
public class CompletedState implements OrderState {@Overridepublic void pay(Order order) {System.out.println("错误:订单已完成!");}@Overridepublic void ship(Order order) {System.out.println("错误:订单已完成!");}@Overridepublic void complete(Order order) {System.out.println("错误:订单已完成!");}
}

 (3)定义上下文

public class Order {private OrderState state;public Order() {this.state = new PendingState(); // 初始状态}// 设置新状态public void setState(OrderState state) {this.state = state;}// 委托给当前状态对象public void pay() {state.pay(this);}public void ship() {state.ship(this);}public void complete() {state.complete(this);}
}

 (4)客户端使用

public class Client {public static void main(String[] args) {Order order = new Order();order.pay();     // 输出:订单支付成功!order.ship();    // 输出:订单已发货!order.complete();// 输出:订单已完成!order.pay();     // 输出:错误:订单已完成!}
}

优缺点分析
 优点
 ✅ 消除条件分支:用多态替代 if-else
 ✅ 符合开闭原则:新增状态无需修改上下文。
 ✅ 符合单一职责:每个状态类封装对应的逻辑,职责单一。
 缺点
 ❌ 状态类数量多(每个状态需一个类)。
 ❌ 状态切换逻辑可能分散在各个状态类中,理解上有一定难度。

状态模式(State) vs 策略模式(Strategy)

对比维度状态模式(State Pattern)策略模式(Strategy Pattern)
核心目的让对象在 内部状态改变 时,行为也随之改变在多个算法/行为中,选择一种合适的策略执行
对象角色每个状态类表示对象的一种状态,封装该状态下的行为每个策略类封装一种算法或行为,可供选择
状态/策略的切换方式对象自身根据条件触发,自动切换到下一个状态外部(调用方) 决定选择哪种策略,通常是 手动注入
是否有顺序状态之间往往有 固定的转换关系(例如:待支付 → 已支付 → 已发货 → 已完成)策略之间 没有顺序,只是不同的实现方式(例如:排序算法可选快速排序、归并排序、冒泡排序)
使用者感知使用者只与 Context 交互,几乎 无感知状态切换使用者 显式选择策略,需要知道不同策略的含义
适用场景- 对象行为依赖内部状态
- 状态切换逻辑复杂
- 需要避免冗长的 if/else
- 需要在运行时灵活选择算法/行为
- 算法需要解耦和封装
- 避免写死在 if/else 中
典型例子- 订单状态流转(未支付/已支付/已发货/已完成)
- 电梯状态(运行/停止/维修)
- 游戏角色状态(行走/攻击/死亡)
- 支付方式(微信/支付宝/银行卡)
- 日志策略(写文件/写数据库/远程发送)
- 排序算法(快排/归并/冒泡)
设计原则体现状态封装,让对象行为随状态变化而变化行为封装,让不同算法可以自由替换
类图区别状态类通常会持有对 Context 的引用,内部可触发状态切换策略类通常 不依赖 Context,只是实现同一个接口

小结:
 状态模式: 对象在不同状态下表现出不同的行为,状态之间有转换关系
 策略模式: 对象在运行时选择不同的算法/行为,策略之间没有固定顺序

6、模板方法(Template Method)

  模板方法模式是一种行为型设计模式,它定义了一个算法的骨架,将某些步骤延迟到子类中实现。模板方法模式的核心思想是"在不改变算法结构的情况下,允许子类重定义算法的某些步骤",从而实现代码复用和扩展。一句话总结:父类规定流程,子类负责实现细节

核心思想:

  1. 算法骨架固定:父类定义算法的流程(如步骤1→步骤2→步骤3)。
  2. 步骤可变:子类可以重写算法的某些步骤,但不改变整体结构。
  3. 好莱坞原则:“Don’t call us, we’ll call you”(父类调用子类,而非子类调用父类)。

组成结构:

  1. 抽象类(AbstractClass):
     定义一个模板方法,规定算法的执行顺序
     模板方法中的某些步骤由抽象方法表示,交由子类实现
     可以包含一些钩子方法(hook method),子类可选择性覆盖
  2. 具体子类(ConcreteClass):
     实现父类中的抽象方法
     覆盖钩子方法(可选),来改变默认行为

在这里插入图片描述

示例代码:

 (1)定义抽象类(算法骨架)

public abstract class Game {// 模板方法(final防止子类覆盖算法结构)public final void play() {initialize();  // 初始化startPlay();   // 开始游戏endPlay();     // 结束游戏}// 抽象步骤(由子类实现)protected abstract void initialize();protected abstract void startPlay();protected abstract void endPlay();
}

 (2)定义具体子类

// 板球游戏
public class Cricket extends Game {@Overrideprotected void initialize() {System.out.println("Cricket Game: Initialized");}@Overrideprotected void startPlay() {System.out.println("Cricket Game: Started");}@Overrideprotected void endPlay() {System.out.println("Cricket Game: Ended");}
}// 足球游戏
public class Football extends Game {@Overrideprotected void initialize() {System.out.println("Football Game: Initialized");}@Overrideprotected void startPlay() {System.out.println("Football Game: Started");}@Overrideprotected void endPlay() {System.out.println("Football Game: Ended");}
}

 (3)客户端使用

public class Client {public static void main(String[] args) {Game cricket = new Cricket();cricket.play(); // 输出:// Cricket Game: Initialized// Cricket Game: Started// Cricket Game: EndedGame football = new Football();football.play();// 输出:// Football Game: Initialized// Football Game: Started// Football Game: Ended}
}

优缺点分析
 优点
 ✅ 代码复用:共享算法骨架。
 ✅ 扩展可控:通过钩子方法限制子类行为。
 ✅ 减少重复代码:避免子类重复流程代码。
 缺点
 ❌ 可能违反里氏替换原则(子类必须实现所有抽象步骤)。
 ❌ 算法结构僵化(父类必须定义完整流程)。

7、迭代器(Iterator)

  迭代器模式是一种行为型设计模式,它提供了一种方法顺序访问聚合对象中的元素,而又无需暴露该对象的底层表示。迭代器模式的核心思想是"将遍历逻辑与聚合对象分离",使两者可以独立变化。

核心思想:

  1. 解耦遍历与存储:迭代器负责遍历,聚合对象负责存储。
  2. 统一访问接口:提供一致的遍历方式(如 hasNext()next()),无论底层数据结构如何。
  3. 支持多种遍历:可定义不同的迭代器实现(如正序、逆序、过滤遍历)。

组成结构:

  1. 迭代器接口(Iterator):定义遍历元素的接口(hasNext()next() 等)
  2. 具体迭代器(ConcreteIterator):实现迭代器接口,负责存储遍历过程中当前位置,并实现迭代逻辑
  3. 聚合接口(Aggregate):定义集合的统一接口(例如:createIterator()
  4. 具体聚合类(ConcreteAggregate):实现聚合接口,返回具体迭代器(如 ListTree
    在这里插入图片描述

代码示例:

 (1)定义迭代器接口

public interface Iterator<T> {boolean hasNext();  // 是否还有元素T next();          // 返回下一个元素
}

 (2)定义聚合接口

public interface Aggregate<T> {Iterator<T> createIterator(); // 创建迭代器
}

 (3)实现具体聚合类

public class BookCollection implements Aggregate<String> {private String[] books = {"Design Patterns", "Clean Code", "Refactoring"};@Overridepublic Iterator<String> createIterator() {return new BookIterator(books); // 返回具体迭代器}
}

 (4)实现具体迭代器

public class BookIterator implements Iterator<String> {private String[] books;private int position = 0;public BookIterator(String[] books) {this.books = books;}@Overridepublic boolean hasNext() {return position < books.length;}@Overridepublic String next() {if (!hasNext()) {throw new NoSuchElementException();}return books[position++];}
}

 (5)客户端使用

public class Client {public static void main(String[] args) {BookCollection collection = new BookCollection();Iterator<String> iterator = collection.createIterator();while (iterator.hasNext()) {System.out.println(iterator.next());}// 输出:// Design Patterns// Clean Code// Refactoring}
}

优缺点分析
 优点
 ✅ 隐藏内部实现:客户端无需知道数据存储细节。
 ✅ 支持多种遍历:可定义不同迭代策略。
 ✅ 符合单一职责原则:集合负责存储,迭代器负责遍历
 缺点
 ❌ 增加类的数量(每个聚合类需对应迭代器)。
 ❌ 简单聚合对象可能过度设计。

迭代器模式 vs for循环

对比点迭代器模式普通for循环
耦合度低(遍历逻辑与存储分离)。高(需知道集合的内部结构,如数组下标)。
扩展性高(可轻松替换迭代策略)。低(修改遍历逻辑需改动代码)。
适用场景复杂数据结构或需要统一接口。简单集合的直接访问。

8、中介者(Mediator)

  中介者模式是一种行为型设计模式,它通过引入一个中介者对象来封装一组对象之间的交互,从而降低对象间的直接耦合。中介者模式的核心思想是"用一个中介对象来封装多个对象之间的交互",使对象之间不需要显式相互引用。

核心思想:

  1. 集中控制交互:将对象间的复杂网状关系变为星型关系(中介者为中心)。
  2. 解耦对象:对象只需与中介者通信,无需知道其他对象的存在。
  3. 简化协作:多对多交互变为一对多(对象→中介者→其他对象)。

组成结构:

  1. 抽象中介者(Mediator):定义与同事对象通信的接口
  2. 具体中介者(ConcreteMediator):实现中介者接口,负责协调各同事对象之间的交互
  3. 抽象同事类(Colleague):持有中介者的引用,把交互请求交给中介者处理
  4. 具体同事类(ConcreteColleague):实现同事的具体行为,在需要与其他同事交互时,委托给中介者

在这里插入图片描述

示例代码:

 (1)抽象中介者

public interface ChatRoom {void sendMessage(String message, User sender); // 发送消息接口
}

 (2)抽象同事类

public abstract class User {protected ChatRoom mediator; // 持有中介者引用protected String name;public User(ChatRoom mediator, String name) {this.mediator = mediator;this.name = name;}public abstract void send(String message);      // 发送消息public abstract void receive(String message);  // 接收消息
}

 (3)具体中介者:聊天室

public class GroupChat implements ChatRoom {private List<User> users = new ArrayList<>();public void addUser(User user) {this.users.add(user);}@Overridepublic void sendMessage(String message, User sender) {for (User user : users) {if (user != sender) { // 不发送给自己user.receive(sender.name + ": " + message);}}}
}

 (4)具体同事:用户

public class ChatUser extends User {public ChatUser(ChatRoom mediator, String name) {super(mediator, name);}@Overridepublic void send(String message) {System.out.println(name + " 发送: " + message);mediator.sendMessage(message, this); // 通过中介者转发}@Overridepublic void receive(String message) {System.out.println(name + " 收到: " + message);}
}

 (5)客户端使用

public class Client {public static void main(String[] args) {// 创建中介者GroupChat chatRoom = new GroupChat();// 创建用户并加入聊天室User alice = new ChatUser(chatRoom, "Alice");User bob = new ChatUser(chatRoom, "Bob");chatRoom.addUser(alice);chatRoom.addUser(bob);// 发送消息(通过中介者)alice.send("Hi, Bob!"); // 输出:// Alice 发送: Hi, Bob!// Bob 收到: Alice: Hi, Bob!bob.send("Hello, Alice!");// 输出:// Bob 发送: Hello, Alice!// Alice 收到: Bob: Hello, Alice!}
}

优缺点分析
 优点
 ✅ 降低耦合:对象间无需直接引用。
 ✅ 简化交互:多对多变为一对多。
 ✅ 集中控制:统一管理交互逻辑。
 ✅ 扩展性好:新增同事对象时,只需注册到中介者中
 缺点
 ❌ 中介者可能变得过于复杂,成为 “上帝类”
 ❌ 所有通信逻辑集中在中介者,维护成本可能变高

9、访问者(Visitor)

  访问者模式是一种行为型设计模式,它允许你将算法与对象结构分离,使得在不修改现有对象结构的前提下,能够为对象结构中的元素添加新的操作。访问者模式的核心思想是"将数据结构和数据操作分离",通过双重分派(Double Dispatch)实现动态绑定。

核心思想:

  1. 分离数据结构与操作:数据结构(如元素集合)保持不变,操作(如算法)可灵活扩展。
  2. 双重分派:通过两次方法调用(元素接受访问者 → 访问者访问元素)实现动态行为。
  3. 集中算法:相关操作集中在访问者类中,而非分散在各元素类中。

组成结构:

  1. 抽象访问者(Visitor):声明一组访问不同元素的接口(如 visitElementAvisitElementB
  2. 具体访问者(ConcreteVisitor):实现访问逻辑,对不同元素做不同的处理
  3. 抽象元素(Element):声明一个 accept(Visitor v) 方法,用于接收访问者,并让访问者“回调”访问逻辑
  4. 具体元素(ConcreteElement):实现 accept() 方法,调用访问者的 visit(this)
  5. 对象结构(ObjectStructure):持有元素的集合,提供 accept(Visitor) 方法,遍历元素并让访问者访问

在这里插入图片描述

示例代码:

 (1)抽象访问者

// 抽象访问者
interface Visitor {void visit(Engineer engineer);void visit(Manager manager);
}

 (2)具体访问者

// 具体访问者:绩效考核
class PerformanceVisitor implements Visitor {@Overridepublic void visit(Engineer engineer) {System.out.println("工程师 " + engineer.name + " 的代码行数:" + engineer.getCodeLines());}@Overridepublic void visit(Manager manager) {System.out.println("经理 " + manager.name + " 的产品数量:" + manager.getProducts());}
}// 具体访问者:薪资统计
class SalaryVisitor implements Visitor {@Overridepublic void visit(Engineer engineer) {System.out.println("工程师 " + engineer.name + " 的工资:" + (engineer.getCodeLines() * 10));}@Overridepublic void visit(Manager manager) {System.out.println("经理 " + manager.name + " 的工资:" + (manager.getProducts() * 5000));}
}

 (3)抽象元素

// 抽象元素
interface Employee {void accept(Visitor visitor);
}

 (4)具体元素

// 具体元素:工程师
class Engineer implements Employee {String name;public Engineer(String name) {this.name = name;}public int getCodeLines() {return 1000; // 模拟数据}@Overridepublic void accept(Visitor visitor) {visitor.visit(this);}
}// 具体元素:经理
class Manager implements Employee {String name;public Manager(String name) {this.name = name;}public int getProducts() {return 5; // 模拟数据}@Overridepublic void accept(Visitor visitor) {visitor.visit(this);}
}

 (5)对象结构

// 对象结构
class Company {private List<Employee> employees = new ArrayList<>();public void addEmployee(Employee e) {employees.add(e);}public void showReport(Visitor visitor) {for (Employee e : employees) {e.accept(visitor);}}
}

 (6)使用

// 测试
public class VisitorPatternDemo {public static void main(String[] args) {Company company = new Company();company.addEmployee(new Engineer("小明"));company.addEmployee(new Manager("小红"));System.out.println("=== 绩效考核 ===");company.showReport(new PerformanceVisitor());System.out.println("\n=== 薪资统计 ===");company.showReport(new SalaryVisitor());}
}

优缺点分析
 优点
 ✅ 符合开闭原则:增加新的操作很容易(新增访问者),不用修改元素类
 ✅ 操作集中:把对某一类对象的操作集中在一个访问者中,便于管理
 ✅ 元素与操作分离:元素类只负责数据结构,不用关心外部操作
 缺点
 ❌ 违反依赖倒置原则:访问者依赖具体元素类(方法 visit(ConcreteElement)
 ❌ 难以扩展元素类:如果需要新增一种元素(例如“实习生”),所有访问者类都要修改
 ❌ 双分派复杂性:需要同时确定元素类型和访问者类型

10、备忘录模式(Memento)

  备忘录模式是一种行为型设计模式,它允许在不破坏封装性的前提下,捕获一个对象的内部状态,并在之后将该状态恢复。备忘录模式的核心思想是"状态快照与恢复",常用于实现撤销(Undo)、历史记录(History)或快照(Snapshot)功能。

核心思想:

  1. 状态捕获:将对象的内部状态保存到独立的对象(备忘录)中。
  2. 状态恢复:从备忘录中恢复对象的历史状态。
  3. 封装保护:备忘录对象对外隐藏原始对象的内部细节,确保封装性。

组成结构:

  1. 发起人(Originator):需要保存状态的对象(如 Editor),负责创建和恢复备忘录。
  2. 备忘录(Memento):存储发起人对象的内部状态(通常是不可变对象)。
  3. 管理者(Caretaker):负责保存和管理备忘录(如 History),但不能直接访问备忘录内容。

在这里插入图片描述

示例代码:

 (1)定义备忘录类

// 备忘录(存储Editor的状态)
public class EditorMemento {private final String content; // 不可变状态public EditorMemento(String content) {this.content = content;}// 仅允许Originator访问内部状态public String getContent() {return content;}
}

 (2)定义发起人类(Editor)

public class Editor {private String content = ""; // 当前文本内容// 输入文本public void type(String text) {content += text;}// 获取当前内容public String getContent() {return content;}// 创建备忘录(保存当前状态)public EditorMemento save() {return new EditorMemento(content);}// 从备忘录恢复状态public void restore(EditorMemento memento) {content = memento.getContent();}
}

 (3)定义管理者类(历史记录)

import java.util.Stack;public class History {private Stack<EditorMemento> mementos = new Stack<>();// 保存状态public void push(EditorMemento memento) {mementos.push(memento);}// 撤销到上一个状态public EditorMemento pop() {if (!mementos.isEmpty()) {return mementos.pop();}return null;}
}

 (4)客户端使用

public class Client {public static void main(String[] args) {Editor editor = new Editor();History history = new History();// 编辑文本并保存状态editor.type("Hello, ");history.push(editor.save()); // 保存状态1editor.type("World!");history.push(editor.save()); // 保存状态2System.out.println("当前内容: " + editor.getContent()); // 输出: Hello, World!// 撤销一次editor.restore(history.pop());System.out.println("撤销后内容: " + editor.getContent()); // 输出: Hello, // 再次撤销editor.restore(history.pop());System.out.println("撤销后内容: " + editor.getContent()); // 输出: (空字符串)}
}

优缺点分析
 优点
 ✅ 状态封装:不暴露对象内部细节。
 ✅ 简化发起人:将状态管理逻辑分离到管理者中。
 ✅ 支持撤销/重做:轻松实现历史记录。
 缺点
 ❌ 内存消耗:频繁保存大对象可能导致内存占用高。
 ❌ 需要深拷贝复杂对象状态(如嵌套引用)。
 ❌ 若新增状态字段,需更新 Memento 的创建/恢复逻辑(与 Originator 同步演进)。

备忘录模式 vs 原型模式

对比点备忘录模式原型模式
目的保存和恢复对象状态。通过克隆创建新对象。
状态访问仅发起人可访问备忘录内容。克隆后的对象可独立修改。
典型应用撤销操作、游戏存档。对象创建成本高时的性能优化。

11、解释器模式(Interpreter)

  解释器模式是一种行为型设计模式,它定义了一种语言的文法表示,并提供一个解释器来解释这种语言中的句子。解释器模式的核心思想是"将领域问题转换为语言规则,并用解释器执行解释",适用于需要解析特定语法或规则的场景(如数学表达式、SQL查询、正则表达式等)。

核心思想:

  1. 语言解析:将问题领域表示为一种语言(如 “3 + 5 * 2”)。
  2. 文法规则:用类表示语言的文法规则(如表达式、运算符)。
  3. 解释执行:通过解释器对象解析并执行语言句子。

组成结构:

  1. 抽象表达式(AbstractExpression):表达式节点统一接口(如 interpret(context))。
  2. 终结符表达式(TerminalExpression):叶子节点,表示字面量、变量等。
  3. 非终结符表达式(NonterminalExpression):组合节点,表示运算、规则组合等。
  4. 上下文(Context):解释所需的外部信息(变量表、函数表等)。
  5. 客户端(Client):把输入按文法解析为 AST,并调用解释。

示例代码:

 (1)定义抽象表达式

public interface Expression {int interpret(Context context); // 解释方法
}

 (2)定义终结符表达式(数字)

public class Number implements Expression {private int value;public Number(int value) {this.value = value;}@Overridepublic int interpret(Context context) {return value; // 直接返回值}
}

 (3)定义非终结符表达式(运算符)

// 加法
public class Add implements Expression {private Expression left;private Expression right;public Add(Expression left, Expression right) {this.left = left;this.right = right;}@Overridepublic int interpret(Context context) {return left.interpret(context) + right.interpret(context);}
}// 乘法
public class Multiply implements Expression {private Expression left;private Expression right;public Multiply(Expression left, Expression right) {this.left = left;this.right = right;}@Overridepublic int interpret(Context context) {return left.interpret(context) * right.interpret(context);}
}

 (4)定义上下文(可选)

public class Context {// 可存储变量表等全局信息private Map<String, Integer> variables = new HashMap<>();public void setVariable(String name, int value) {variables.put(name, value);}public int getVariable(String name) {return variables.getOrDefault(name, 0);}
}

 (5)客户端构建语法树并解释

public class Client {public static void main(String[] args) {// 构建表达式:3 + 5 * 2Expression expr = new Add(new Number(3),new Multiply(new Number(5), new Number(2)));// 解释执行Context context = new Context();int result = expr.interpret(context);System.out.println("结果: " + result); // 输出: 13}
}

优缺点分析
 优点
 ✅ 易于扩展文法:新增规则只需添加表达式类。
 ✅ 实现简单文法直观:适合领域特定语言(DSL)。
 缺点
 ❌ 类爆炸:复杂文法难以维护(规则多时类爆炸)。
 ❌ 性能一般:递归解释 + 对象分配较多,不如编译/代码生成快。
 ❌ 复杂语法维护难:左递归、二义性、错误恢复需要大量工程投入。

http://www.dtcms.com/a/335194.html

相关文章:

  • IO流-打印流
  • leetcode hot100数组:缺失的第一个正数
  • 洛谷B3924 [GESP202312 二级] 小杨的H字矩阵
  • 洛谷B3865 [GESP202309 二级] 小杨的 X 字矩阵(举一反三)
  • CSDN部分内容改为视频转到B站-清单
  • 如何解决pip安装报错ModuleNotFoundError: No module named ‘opencv-python’问题
  • Cloudflare Tunnel 使用SAAS回源加速配置教程
  • 配置 Docker 镜像加速,解决 docker pull 拉取镜像失败、docker search 查询镜像失败等问题
  • Agent中的memory
  • 异构数据库兼容力测评:KingbaseES 与 MySQL 的语法・功能・性能全场景验证解析
  • MySQL性能优化:10个关键参数调整指南
  • ISO27001 高阶架构 之 支持 -2
  • 概率论基础教程第3章条件概率与独立性(三)
  • 从频繁告警到平稳发布:服务冷启动 CPU 风暴优化实践00
  • implement libwhich for Windows
  • 全面解析Tomcat生命周期原理及其关键实现细节
  • 牛 CDR3 单抗:抗病毒领域的 “纳米级精准导弹”
  • 掌握长尾关键词优化SEO技巧
  • [创业之路-550]:公司半年度经营分析会 - 常见差距与根因分析示例
  • Hugging Face 与 NLP
  • 【JavaEE】(13) Spring Web MVC 入门
  • (论文速读)低光照图像增强综述(一)
  • Web全栈项目中健康检查API的作用(现代云原生应用标准实践)(health check、healthcheck、livenessProbe、健康探针)
  • 从舒适度提升到能耗降低再到安全保障,楼宇自控作用关键
  • 机器学习——PCA算法
  • 《软件工程导论》实验报告五 设计建模工具的使用(一)类图
  • 单目 BEV有哪些开源项目
  • redis基本类型之哈希
  • 《后室Backrooms》中文版,购物误入异空间,怪物追逐,第一人称冒险逃生
  • 模版模版模版