# JavaDesignPattern **Repository Path**: maoxiaojiu9/JavaDesignPattern ## Basic Information - **Project Name**: JavaDesignPattern - **Description**: Java版设计模式学习 - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2025-05-20 - **Last Updated**: 2025-12-29 ## Categories & Tags **Categories**: Uncategorized **Tags**: Java ## README # Java版设计模式 # 一、设计模式的目的 设计模式的主要目的是提高代码的: | 目标 | 说明 | |:---------|:-------------------| | **可复用性** | 同一解决方案可以用于多个项目或模块。 | | **可维护性** | 结构清晰、职责明确,易于理解和修改。 | | **可扩展性** | 新功能容易添加,符合开闭原则。 | | **灵活性** | 能适应需求变化,减少硬编码依赖。 | | **解耦性** | 模块之间依赖抽象,降低耦合度。 | # 二、七大设计原则 | 原则名称 | 英文缩写 | 核心思想 | |:-------|:--------------------------------------|:---------------------| | 单一职责原则 | SRP (Single Responsibility Principle) | 一个类/方法只做一件事 | | 开闭原则 | OCP (Open-Closed Principle) | 对扩展开放,对修改关闭 | | 里氏替换原则 | LSP (Liskov Substitution Principle) | 子类应能替换父类而不破坏逻辑 | | 接口隔离原则 | ISP (Interface Segregation Principle) | 定义细粒度接口,客户端不依赖不需要的方法 | | 依赖倒置原则 | DIP (Dependency Inversion Principle) | 依赖抽象(接口),不依赖具体实现 | | 合成复用原则 | CRP (Composite Reuse Principle) | 优先使用组合而不是继承来复用代码 | | 迪米特法则 | LoD (Law of Demeter) | 最少知道原则,降低对象之间的耦合 | ## 1. **单一职责原则 (SRP)** - **定义**:一个类或方法只负责一项职责。 - **优点**:提高可读性、可测试性和可维护性。 - **示例**: - 一个 `UserService` 类只处理用户相关逻辑,不处理订单。 ![单一职责原则.png](img/01principle/单一职责原则.png) ## 2. **开闭原则 (OCP)** - **定义**:软件实体(类、模块、函数等)应该对扩展开放,对修改关闭。 - **优点**:增强系统的可扩展性和可维护性。 - **示例**: - 使用策略模式动态切换算法,而无需修改原有代码。 ![开闭原则.png](img/01principle/开闭原则.png) ## 3. **里氏替换原则 (LSP)** - **定义**:子类必须能够替换其父类,而不导致程序出错。 - **优点**:保证继承关系的合理性。 - **示例**: - `Bird` 是父类,`Penguin` 继承它但不能飞,如果调用 `fly()` 就会出错 → 违反 LSP。 ![里氏替换原则.png](img/01principle/里氏替换原则.png) ## 4. **接口隔离原则 (ISP)** - **定义**:客户端不应被迫依赖于它不使用的接口。 - **优点**:避免“胖接口”带来的副作用。 - **示例**: - 不要把所有功能都放在一个大接口中,而是拆分成多个小接口。 ![接口隔离原则.png](img/01principle/接口隔离原则.png) ## 5. **依赖倒置原则 (DIP)** - **定义**:高层模块不应该依赖低层模块,都应该依赖抽象;抽象不应该依赖细节,细节应该依赖抽象。 - **优点**:解耦,提升灵活性。 - **示例**: - `Car` 依赖 `Engine` 接口,而不是具体的 `PetrolEngine` 实现。 ![依赖倒置原则.png](img/01principle/依赖倒置原则.png) **依赖传递的三种主要方式** | 方式 | 描述 | 示例 | | :------------- | :------------------------------- | :---------------------------------------------------- | | 🟢 构造函数注入 | 通过构造函数传入依赖 | `new NotificationService(emailService)` | | 🟡 Setter 注入 | 通过 setter 方法设置依赖 | `notificationService.setMessageService(emailService)` | | 🔵 接口注入 | 通过接口方法注入依赖(较少使用) | 在接口中定义注入方法 | ## 6. **合成复用原则 (CRP)** - **定义**:尽量使用组合或聚合代替继承来达到复用的目的。 - **优点**:减少类间耦合,提高灵活性。 - **示例**: - `Car` 包含一个 `Engine` 对象,而不是继承 `Engine`。 ![合成复用原则.png](img/01principle/合成复用原则.png) ## 7. **迪米特法则 (LoD)** - **定义**:一个对象应当对其他对象保持最少的了解。 - **优点**:降低耦合,提高模块独立性。 - **示例**: - 类 A 调用类 B 的方法,但不要直接访问 B 内部的 C 对象。 - 只和“直接朋友”通信,封装细节逻辑 - | 类型 | 示例说明 | | :--------------------------------- | :--------------------- | | **当前对象本身(this)** | 自己调用自己的方法 | | **方法的参数对象** | 传入的对象可以直接调用 | | **当前对象所创建的对象** | new 出来的对象可以调用 | | **当前对象的成员变量对象** | 属性对象可以直接调用 | | **当前对象直接持有的集合中的元素** | 如 List 中的每个元素 | ![迪米特法则.png](img/01principle/迪米特法则.png) # 三、UML类图 ## UML 类图基本元素 | 元素 | 描述 | | :-------------------- | :--------------------------------------- | | **类(Class)** | 用矩形表示,包含三部分:类名、属性、方法 | | **接口(Interface)** | 表示为带 `<>` 标签的类 | | **关系** | 包括继承、实现、依赖、关联、聚合、组合等 | ## UML 类图中常见关系说明 | 关系 | 图形表示 | 说明 | | :------------------------- | :-------------- | :----------------------- | | **继承(Generalization)** | 实线 + 空心箭头 | 子类继承父类 | | **实现(Realization)** | 虚线 + 空心箭头 | 类实现接口 | | **依赖(Dependency)** | 虚线 + 箭头 | A 的变化影响 B | | **关联(Association)** | 实线 | A 和 B 是朋友关系 | | **聚合(Aggregation)** | 实线 + 空心菱形 | 整体和部分,生命周期不同 | | **组合(Composition)** | 实线 + 实心菱形 | 强整体/部分关系,共生死 | # 四、23种设计模式 ## 1.创建型模式(Creational Patterns) 负责对象的创建,隐藏对象实例化的细节。 | 模式名称 | 英文名 | 简要说明 | | :----------- | :--------------- | :--------------------------------------------------- | | 工厂方法模式 | Factory Method | 定义一个用于创建对象的接口,让子类决定实例化哪一个类 | | 抽象工厂模式 | Abstract Factory | 提供一个创建一系列相关或相互依赖对象的家族接口 | | 单例模式 | Singleton | 保证一个类只有一个实例,并提供全局访问点 | | 建造者模式 | Builder | 将一个复杂对象的构建与其表示分离 | | 原型模式 | Prototype | 通过克隆已有对象来创建新对象 | ------ ## 2.结构型模式(Structural Patterns) 处理对象和类之间的组合方式,关注如何组合对象形成更大的结构。 | 模式名称 | 英文名 | 简要说明 | | :--------- | :-------- | :------------------------------- | | 适配器模式 | Adapter | 使不兼容接口的对象可以协同工作 | | 装饰器模式 | Decorator | 动态地给对象添加职责 | | 代理模式 | Proxy | 控制对象的访问 | | 组合模式 | Composite | 树形结构处理(部分-整体) | | 外观模式 | Facade | 提供统一接口简化子系统使用 | | 桥接模式 | Bridge | 解耦抽象与其实现,使其可独立变化 | | 享元模式 | Flyweight | 共享细粒度对象以节省资源 | ------ ## 3.行为型模式(Behavioral Patterns) 描述对象之间通信的方式及职责分配。 | 模式名称 | 英文名 | 简要说明 | | :----------- | :---------------------- | :--------------------------------- | | 观察者模式 | Observer | 一对多的依赖通知机制 | | 策略模式 | Strategy | 定义算法族,可动态切换 | | 责任链模式 | Chain of Responsibility | 请求的处理链式传递 | | 命令模式 | Command | 将请求封装为对象 | | 模板方法模式 | Template Method | 定义算法骨架,子类实现具体步骤 | | 迭代器模式 | Iterator | 提供一种顺序访问聚合对象元素的方法 | | 中介者模式 | Mediator | 减少对象间的直接耦合 | | 访问者模式 | Visitor | 在不修改对象的前提下定义新操作 | | 备忘录模式 | Memento | 捕获并保存对象内部状态以便恢复 | | 状态模式 | State | 对象状态改变时行为随之变化 | | 解释器模式 | Interpreter | 定义语言的文法并解释执行 | ------ ## 总结记忆口诀(按分类) - 创建型:工单建原抽 - 工厂方法、单例、建造者、原型、抽象工厂 - 结构型:代外组桥适享 - 代理、外观、组合、桥接、适配器、享元 - 行为型:观察策略责任命令模板迭代中介访问备忘状态解释 - 观察者、策略、责任链、命令、模板方法、迭代器、中介者、访问者、备忘录、状态、解释器 # 五、创建型模式 ## 1.单例模式 单例模式(Singleton Pattern)是 创建型设计模式 中的一种,用于确保一个类在整个应用程序生命周期中只有一个实例存在,并提供一个全局访问点。 ### 单例模式的核心思想 - 私有化构造器:防止外部通过 new 创建对象 - 内部持有唯一实例:静态变量保存唯一实例 - 对外提供访问方法:通常是一个 public static 方法 ### 1.1饿汉式(静态常量)线程安全 特点:简单、线程安全,但可能浪费资源(即使未使用也初始化) ```java /** * 饿汉式(静态常量) */ public class SingletonTest01 { public static void main(String[] args) { System.out.println(Singleton.getInstance()); System.out.println(Singleton.getInstance()); System.out.println(Singleton.getInstance()); System.out.println(Singleton.getInstance()); } } class Singleton { // 类加载时就初始化 private static final Singleton INSTANCE = new Singleton(); // 构造器私有化 private Singleton() { } // 提供公共的静态方法,返回实例对象 public static Singleton getInstance() { return INSTANCE; } } ``` ### 1.2饿汉式(静态代码块)线程安全 ```java /** * 饿汉式(静态代码块) */ public class SingletonTest02 { public static void main(String[] args) { System.out.println(Singleton.getInstance()); System.out.println(Singleton.getInstance()); System.out.println(Singleton.getInstance()); System.out.println(Singleton.getInstance()); } } class Singleton { // 类加载时就初始化 private static final Singleton INSTANCE; static { INSTANCE = new Singleton(); } // 构造器私有化 private Singleton() { } // 提供公共的静态方法,返回实例对象 public static Singleton getInstance() { return INSTANCE; } } ``` ### 1.3懒汉式(线程不安全) ```java /** * 懒汉式(线程不安全) */ public class SingletonTest03 { public static void main(String[] args) { // System.out.println(Singleton.getInstance()); // System.out.println(Singleton.getInstance()); // System.out.println(Singleton.getInstance()); // System.out.println(Singleton.getInstance()); // 模拟10个线程并发获取单例对象 for (int i = 1; i <= 10; i++) { new Thread(() -> { System.out.println(Thread.currentThread().getName() + " 获取到的实例:" + Singleton.getInstance()); }, "线程-" + i).start(); } } } class Singleton { private static Singleton INSTANCE; // 构造器私有化 private Singleton() { } // 提供公共的静态方法,返回实例对象 public static Singleton getInstance() { if (INSTANCE == null) { INSTANCE = new Singleton(); } return INSTANCE; } } ``` ### 1.4 懒汉式(线程安全、同步方法) 效率低,不推荐 ```java /** * 懒汉式(线程安全、同步方法) */ public class SingletonTest04 { public static void main(String[] args) { // 模拟10个线程并发获取单例对象 for (int i = 1; i <= 10; i++) { new Thread(() -> { System.out.println(Thread.currentThread().getName() + " 获取到的实例:" + Singleton.getInstance()); }, "线程-" + i).start(); } } } class Singleton { private static Singleton INSTANCE; // 构造器私有化 private Singleton() { } // 提供公共的静态方法,返回实例对象,同步方法解决线程安全 public static synchronized Singleton getInstance() { if (INSTANCE == null) { INSTANCE = new Singleton(); } return INSTANCE; } } ``` ### 1.5懒汉式(线程安全、同步代码块) if (INSTANCE == null) ,不能使用 ```java /** * 懒汉式(线程安全、同步代码块) */ public class SingletonTest05 { public static void main(String[] args) { // 模拟10个线程并发获取单例对象 for (int i = 1; i <= 10; i++) { new Thread(() -> { System.out.println(Thread.currentThread().getName() + " 获取到的实例:" + Singleton.getInstance()); }, "线程-" + i).start(); } } } class Singleton { private static Singleton INSTANCE; // 构造器私有化 private Singleton() { } // 提供公共的静态方法,返回实例对象,同步代码块解决线程安全 public static Singleton getInstance() { if (INSTANCE == null) { synchronized (Singleton.class) { INSTANCE = new Singleton(); } } return INSTANCE; } } ``` ### 1.6 双重检查锁定(推荐) 特点:线程安全 + 延迟加载 + 性能较好 ```java /** * 双重检查锁定 * 特点:线程安全 + 延迟加载 + 性能较好 */ public class SingletonTest06 { public static void main(String[] args) { // 模拟10个线程并发获取单例对象 for (int i = 1; i <= 10; i++) { new Thread(() -> { System.out.println(Thread.currentThread().getName() + " 获取到的实例:" + Singleton.getInstance()); }, "线程-" + i).start(); } } } class Singleton { private static Singleton INSTANCE; // 构造器私有化 private Singleton() { } // 提供公共的静态方法,返回实例对象,双重检查锁定 public static Singleton getInstance() { if (INSTANCE == null) { synchronized (Singleton.class) { if (INSTANCE == null) { INSTANCE = new Singleton(); } } } return INSTANCE; } } ``` ### 1.7 静态内部类(推荐) 1. **延迟加载(Lazy Initialization)** - 外部类 `Singleton` 被加载时,并不会立即创建实例; - 只有当调用 `getInstance()` 方法时,才会触发 `SingletonHolder` 类的加载; - 在 `SingletonHolder` 类加载时,才创建 `Singleton` 的唯一实例。 2. **线程安全(Thread-safe)** - JVM 在类加载机制中天然地保证了线程安全; - 即使多个线程并发调用 `getInstance()`,也只会初始化一次 `INSTANCE`。 3. **避免同步开销** - 不需要使用 `synchronized` 关键字或 `volatile` 变量; - 没有多线程竞争的问题,性能更优。 ```java /** * 静态内部类(推荐) */ public class SingletonTest07 { public static void main(String[] args) { // 模拟10个线程并发获取单例对象 for (int i = 1; i <= 10; i++) { new Thread(() -> { System.out.println(Thread.currentThread().getName() + " 获取到的实例:" + Singleton.getInstance()); }, "线程-" + i).start(); } } } class Singleton { // 构造器私有化 private Singleton() { } // 静态内部类 private static class SingletonInstance { private static final Singleton INSTANCE = new Singleton(); } // 提供公共的静态方法,返回实例对象 public static Singleton getInstance() { return SingletonInstance.INSTANCE; } } ``` ### 1.8 枚举单例(最安全的方式) ```java /** * 枚举单例 */ public class SingletonTest08 { public static void main(String[] args) { // 模拟10个线程并发获取单例对象 for (int i = 1; i <= 10; i++) { new Thread(() -> { System.out.println(Thread.currentThread().getName() + " 获取到的实例:" + Singleton.INSTANCE.hashCode()); }, "线程-" + i).start(); } } } enum Singleton{ INSTANCE; public void doSomething() { System.out.println("Do something..."); } } ``` ### 使用场景 | 使用场景 | 是否推荐 | 说明 | | :--------------- | :------- | :----------------------- | | 资源管理类 | ✅ 是 | 如数据库连接池、日志工厂 | | 配置管理器 | ✅ 是 | 全局配置只需加载一次 | | 任务调度器 | ✅ 是 | 管理定时任务 | | 工具类 | ✅ 是 | 无状态、通用性强 | | 第三方客户端 | ✅ 是 | 减少资源消耗 | | 有状态对象 | ❌ 否 | 容易引起并发问题 | | 每次都需要新实例 | ❌ 否 | 违反单例初衷 | ## 2.简单工厂模式 简单工厂模式(Simple Factory Pattern)是一种创建型设计模式,它通过一个工厂类来封装对象的创建逻辑,使得客户端无需关心具体对象的实例化过程,只需要传入所需的类型参数即可获取对应的对象。 ### 核心思想 - 将对象的创建集中到一个工厂类中处理。 - 客户端通过工厂类获取对象,而不需要直接使用 new 来实例化具体类。 ### 简单工厂模式的组成角色 - 产品接口或抽象类 Product:定义产品的公共接口或行为。 - 具体产品类 ConcreteProductA, ConcreteProductB:实现产品接口的具体类。 - 工厂类 Factory:提供一个静态方法(如 createProduct),根据输入参数返回不同的产品实例。 ![02简单工厂模式.png](img/02creational/02简单工厂模式.png) ### 优点 - 解耦客户端与具体产品类之间的依赖。 - 提高扩展性,新增产品时只需修改工厂类(符合开闭原则的部分实现)。 ### 缺点 - 工厂类职责过重,违反单一职责原则。 - 新增产品需要修改工厂类代码,不符合开闭原则(对扩展开放、对修改关闭)。 ### 示例代码 ```java // 抽象产品类 interface Product { void use(); } // 具体产品A class ConcreteProductA implements Product { public void use() { System.out.println("Using Product A"); } } // 具体产品B class ConcreteProductB implements Product { public void use() { System.out.println("Using Product B"); } } // 工厂类 class SimpleFactory { public static Product createProduct(String type) { if (type.equals("A")) { return new ConcreteProductA(); } else if (type.equals("B")) { return new ConcreteProductB(); } return null; } } // 客户端调用示例 public class Client { public static void main(String[] args) { Product product = SimpleFactory.createProduct("A"); product.use(); // 输出: Using Product A } } ``` ### 使用场景 - 产品种类较少且不频繁变化。 - 不希望客户端知道具体类名,只希望通过参数获取对应对象。 - 适用于统一管理对象创建入口,简化客户端调用。 ## 3.工厂方法模式 **工厂方法模式(Factory Method Pattern)** 是一种 **创建型设计模式**,它定义了一个用于创建对象的接口,但由子类决定实例化哪一个类。工厂方法将类的实例化延迟到其子类。 ### 模式结构 1. `Product`(产品接口或抽象类): - 定义产品的公共接口或行为。 2. `ConcreteProductA`, `ConcreteProductB`(具体产品类): - 实现 `Product` 接口的具体类。 3. `Factory`(工厂接口或抽象类): - 声明一个工厂方法 `createProduct()`,返回一个 `Product` 对象。 - 通常是一个抽象类或接口。 4. `ConcreteFactoryA`, `ConcreteFactoryB`(具体工厂类): - 实现工厂方法,返回对应的具体产品实例。 ![03工厂方法模式.png](img/02creational/03工厂方法模式.png) ------ ### 示例代码 ```java // 产品接口 interface Product { void use(); } // 具体产品A class ConcreteProductA implements Product { public void use() { System.out.println("使用产品 A"); } } // 具体产品B class ConcreteProductB implements Product { public void use() { System.out.println("使用产品 B"); } } // 工厂接口 interface Factory { Product createProduct(); // 工厂方法 } // 具体工厂A class ConcreteFactoryA implements Factory { public Product createProduct() { return new ConcreteProductA(); } } // 具体工厂B class ConcreteFactoryB implements Factory { public Product createProduct() { return new ConcreteProductB(); } } // 客户端代码 public class Client { public static void main(String[] args) { Factory factoryA = new ConcreteFactoryA(); Product productA = factoryA.createProduct(); productA.use(); // 输出:使用产品 A Factory factoryB = new ConcreteFactoryB(); Product productB = factoryB.createProduct(); productB.use(); // 输出:使用产品 B } } ``` ------ ### 工厂方法模式 vs 简单工厂模式 | 特性 | 简单工厂模式 | 工厂方法模式 | | :------------- | :--------------------- | :--------------------------------------- | | 工厂类是否固定 | 是 | 否(由子类决定) | | 扩展性 | 新增产品需修改工厂类 | 符合开闭原则,扩展只需新增工厂类和产品类 | | 职责单一性 | 不符合(职责过重) | 符合(每个工厂只负责一类产品) | | 适用场景 | 产品种类少、变化不频繁 | 产品种类多、需要灵活扩展 | ### 使用场景 - 你希望系统与具体产品的创建解耦。 - 产品种类较多,并且未来可能继续扩展。 - 需要符合 开闭原则,即对扩展开放,对修改关闭。 - 多个产品族,每个工厂只生产一组相关的产品。 ## 4.抽象工厂模式 抽象工厂模式(Abstract Factory Pattern)是一种**创建型设计模式**,它用于在不指定具体类的情况下,创建一组相关或依赖对象的家族。 ### 核心思想 - 提供一个接口,用于创建一系列相关的或相互依赖的对象,而无需指定它们具体的类。 - 适用于**多产品族、单产品等级结构**的情况。 ### 主要组成 1. **抽象工厂(Abstract Factory)** 定义一组用于创建产品对象的接口,通常是一个接口或抽象类,如 `AbstractFactory`。 2. **具体工厂(Concrete Factory)** 实现抽象工厂中的方法,用来创建具体的产品对象,例如 `ConcreteFactoryA` 和 `ConcreteFactoryB`。 3. **抽象产品(Abstract Product)** 定义产品的公共接口,比如 `ProductA` 和 `ProductB`。 4. **具体产品(Concrete Product)** 实现抽象产品接口的具体类,如 `ConcreteProductA1`, `ConcreteProductA2`, `ConcreteProductB1`, `ConcreteProductB2` 等。 5. **客户端(Client)** 使用抽象工厂和抽象产品提供的接口来操作具体的产品对象,而不需要关心其具体实现。 ![04抽象工厂模式.png](img/02creational/04抽象工厂模式.png) ### 示例代码 ```java // 抽象产品A public interface ProductA { void operationA(); } // 具体产品A1 public class ConcreteProductA1 implements ProductA { public void operationA() { System.out.println("ProductA1 operation"); } } // 抽象产品B public interface ProductB { void operationB(); } // 具体产品B1 public class ConcreteProductB1 implements ProductB { public void operationB() { System.out.println("ProductB1 operation"); } } // 抽象工厂 public interface AbstractFactory { ProductA createProductA(); ProductB createProductB(); } // 具体工厂1 public class ConcreteFactory1 implements AbstractFactory { public ProductA createProductA() { return new ConcreteProductA1(); } public ProductB createProductB() { return new ConcreteProductB1(); } } // 客户端代码 public class Client { public static void main(String[] args) { AbstractFactory factory = new ConcreteFactory1(); ProductA productA = factory.createProductA(); ProductB productB = factory.createProductB(); productA.operationA(); // 输出: ProductA1 operation productB.operationB(); // 输出: ProductB1 operation } } ``` ### 应用场景 - 当需要创建一组相关或依赖对象的组合,并且希望与这些对象的具体类解耦时。 - 需要支持多个产品族,每个产品族中包含不同种类的产品。 - 在系统中需要动态切换多个产品族的实现时。 ### 优点 - 封装了具体类的创建过程,使得客户端无需知道具体类的实现。 - 易于扩展新的产品族,符合开闭原则。 - 确保同一产品族中的对象之间的一致性和兼容性。 ### 缺点 - 增加系统的复杂度,增加了接口和类的数量。 - 扩展新产品类型较为困难,需要修改抽象工厂接口及其所有实现类。 ## 5.原型模式 原型模式(Prototype Pattern)是一种**创建型设计模式**,它通过**复制已有对象**来创建新对象,而不是通过实例化类的方式。这种模式适用于创建对象的成本比较大或者步骤比较复杂的情况下。 ### 核心思想 - **通过克隆一个已有的对象来生成新对象**,客户端无需关心对象的创建过程。 - 被复制的对象被称为“原型(Prototype)”。 ![05原型模式.png](img/02creational/05原型模式.png) ### 适用场景 1. 创建对象的成本较大(例如需要频繁初始化数据库、网络请求等)。 2. 对象的创建过程复杂,但其结构适合拷贝。 3. 希望屏蔽对象创建细节,统一使用接口创建对象。 ------ ### 示例代码 ```java // 1. 实现 Cloneable 接口 public class Prototype implements Cloneable { private String field; public String getField() { return field; } public void setField(String field) { this.field = field; } // 2. 重写 clone 方法 @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } } ``` ```java Prototype prototype = new Prototype(); prototype.setField("原始对象"); Prototype cloned = (Prototype) prototype.clone(); // 克隆对象 System.out.println(cloned.getField()); // 输出:原始对象 ``` ------ ### 优点 | 优点 | 描述 | | :------------- | :------------------------------------------------------ | | `性能好` | 直接克隆对象比重新创建更高效,尤其是创建成本高的情况。 | | `简化对象创建` | 客户端无需知道对象的具体类,只需要调用 `clone()` 即可。 | | `解耦` | 避免了与具体类的紧耦合,扩展性强。 | ------ ### 缺点 | 缺点 | 描述 | | :------------------------- | :----------------------------------------------------------- | | `深拷贝和浅拷贝问题` | 如果对象包含引用类型字段,需实现深拷贝逻辑,否则会共享内部对象。 | | `违背开闭原则(部分情况)` | 每新增一个原型类都需要重写 `clone()` 方法,不够灵活。 | ------ ### 总结 原型模式是一种通过**克隆已有对象**来创建新对象的设计模式,适用于对象创建成本高或过程复杂的情况。它的核心是利用 `clone()` 方法快速生成对象副本,从而提升性能并降低耦合度。 ### Spring 如何创建原型模式 Bean 1.BeanDefinition 中的作用域配置 ```java public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement { void setScope(String scope); String getScope(); } ``` 获取xml或者注解中的作用域 ```java @Component @Scope("prototype") public class MyBean { ... } ``` 2.创建 Bean 的流程(AbstractBeanFactory) ```java protected T doGetBean(...) { // ... if (mbd.isSingleton()) { // 单例模式:从缓存获取或创建一次 bean = (T) getSingleton(beanName, () -> createBean(beanName, mbd, args)); } else if (mbd.isPrototype()) { // 原型模式:每次都调用 createBean 创建新实例 Object prototypeInstance = createBean(beanName, mbd, args); bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd); } else { // 其他作用域(如 request、session) } // ... } ``` 3.createBean 方法(AbstractAutowireCapableBeanFactory) ```java @Override protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) { // 1. 实例化 Bean Object beanInstance = instantiateBean(beanName, mbd); // 2. 属性填充 populateBean(beanName, mbd, instanceWrapper); // 3. 初始化 exposedObject = initializeBean(beanName, exposedObject, mbd); return exposedObject; } ``` | 步骤 | 描述 | | :--------------------------- | :---------------------------------------- | | `1. 配置 BeanDefinition` | 设置 `scope="prototype"` | | `2. doGetBean()` 判断作用域 | 发现是 prototype,直接调用 `createBean()` | | `3. createBean()` 创建新实例 | 包括实例化、属性注入、初始化 | | `4. 不缓存也不自动销毁` | 每次都是新对象,销毁需手动处理 | ### 深拷贝和浅拷贝 #### 浅拷贝 浅拷贝只复制对象本身及其**基本类型字段的值**,对于对象中的**引用类型字段**,只会复制引用地址(即指向同一个对象),不会创建新的对象。 ##### 实现方式 - 默认实现 `clone()` 方法(继承 `Cloneable` 接口)。 - 或手动赋值每个字段。 ##### 特点 - 原始对象和拷贝对象共享 `Address` 实例。 - 修改其中一个对象的 `address` 字段会影响另一个。 ------ #### 二、深拷贝 深拷贝不仅复制对象本身,还会递归地复制对象中所有引用类型的字段,确保新对象与原对象完全独立。 ##### 实现方式 方式1:手动重写 `clone()`,对引用对象也调用 `clone()` ```java public class Person implements Cloneable { private String name; private Address address; @Override protected Object clone() throws CloneNotSupportedException { Person person = (Person) super.clone(); person.address = (Address) this.address.clone(); // 深拷贝引用对象 return person; } } ``` 方式2:序列化(推荐用于复杂对象) ```java public static T deepCopy(T object) { ByteArrayOutputStream bos = null; ObjectOutputStream oos = null; ByteArrayInputStream bis = null; ObjectInputStream ois = null; try { bos = new ByteArrayOutputStream(); oos = new ObjectOutputStream(bos); oos.writeObject(object); bis = new ByteArrayInputStream(bos.toByteArray()); ois = new ObjectInputStream(bis); return (T) ois.readObject(); } catch (Exception e) { throw new RuntimeException("深拷贝失败", e); } finally { // 关闭流资源 if (ois != null) { try { ois.close(); } catch (IOException ignored) {} } if (bis != null) { try { bis.close(); } catch (IOException ignored) {} } if (oos != null) { try { oos.close(); } catch (IOException ignored) {} } if (bos != null) { try { bos.close(); } catch (IOException ignored) {} } } } ``` ##### 特点 - 原始对象和拷贝对象互不影响。 - 更安全,但性能开销更大。 ## 6.建造者模式 建造者模式(Builder Pattern)是 **创建型设计模式** 的一种,用于将一个复杂对象的构建与其表示分离,使得同样的构建过程可以创建不同的表示。 它适用于构建具有多个组成部分、且构建逻辑较为复杂的对象。例如:组装一台电脑、生成一份文档、构造一个套餐等。 ### 核心思想 > **“将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。”** 核心角色: | 角色 | 描述 | | :------------------------------ | :-------------------------------------------------- | | `Product`(产品类) | 要构建的最终复杂对象 | | `Builder`(抽象建造者) | 定义构建步骤的接口(如 buildPartA(), buildPartB()) | | `ConcreteBuilder`(具体建造者) | 实现 Builder 接口,完成具体部件的构建 | | `Director`(指挥者) | 指挥建造过程,使用 Builder 构建最终对象 | ![06建造者模式.png](img/02creational/06建造者模式.png) ### 适用场景 - 当一个对象的构建过程比较复杂,包含多个组件或步骤。 - 同一个构建过程可以产生不同的产品(即不同的组合方式)。 - 需要隔离构建和使用,用户只需知道最终使用的对象,不需要了解构建细节。 - 构建逻辑变化频繁,但使用方式保持不变。 ### 示例代码 1. 定义产品类(Product) ```java public class Computer { private String cpu; private String ram; private String storage; public void setCPU(String cpu) { this.cpu = cpu; } public void setRAM(String ram) { this.ram = ram; } public void setStorage(String storage) { this.storage = storage; } @Override public String toString() { return "Computer{" + "cpu='" + cpu + '\'' + ", ram='" + ram + '\'' + ", storage='" + storage + '\'' + '}'; } } ``` 2. 抽象建造者(Builder) ```java public interface ComputerBuilder { void buildCPU(); void buildRAM(); void buildStorage(); Computer getComputer(); } ``` 3. 具体建造者(ConcreteBuilder) ```java // 游戏玩家电脑建造者 public class GamingComputerBuilder implements ComputerBuilder { private Computer computer; public GamingComputerBuilder() { computer = new Computer(); } @Override public void buildCPU() { computer.setCPU("Intel i9"); } @Override public void buildRAM() { computer.setRAM("64GB DDR4"); } @Override public void buildStorage() { computer.setStorage("2TB NVMe SSD"); } @Override public Computer getComputer() { return computer; } } // 办公电脑建造者 public class OfficeComputerBuilder implements ComputerBuilder { private Computer computer; public OfficeComputerBuilder() { computer = new Computer(); } @Override public void buildCPU() { computer.setCPU("Intel i5"); } @Override public void buildRAM() { computer.setRAM("16GB DDR4"); } @Override public void buildStorage() { computer.setStorage("512GB SSD"); } @Override public Computer getComputer() { return computer; } } ``` 4. 指挥者(Director) ```java public class Director { private ComputerBuilder builder; public void setBuilder(ComputerBuilder builder) { this.builder = builder; } public void constructComputer() { builder.buildCPU(); builder.buildRAM(); builder.buildStorage(); } } ``` 5. 客户端调用 ```java public class Client { public static void main(String[] args) { Director director = new Director(); // 创建游戏电脑 ComputerBuilder gamingBuilder = new GamingComputerBuilder(); director.setBuilder(gamingBuilder); director.constructComputer(); Computer gamingPC = gamingBuilder.getComputer(); System.out.println("Gaming PC: " + gamingPC); // 创建办公电脑 ComputerBuilder officeBuilder = new OfficeComputerBuilder(); director.setBuilder(officeBuilder); director.constructComputer(); Computer officePC = officeBuilder.getComputer(); System.out.println("Office PC: " + officePC); } } ``` ### 优点 | 优点 | 描述 | | :--------------- | :----------------------------------------------- | | ✅ 封装性好 | 客户端无需关心构建细节,只需要指定具体建造者即可 | | ✅ 解耦构建与使用 | 构建过程和最终对象的使用完全解耦 | | ✅ 易于扩展 | 新增一个具体建造者非常容易,符合开闭原则 | | ✅ 可控制构建流程 | 指挥者可以灵活控制构建顺序和内容 | ### 缺点 | 缺点 | 描述 | | :--------------- | :--------------------------------------------- | | ❌ 类数量多 | 每个具体建造者都需要一个类,增加了系统的复杂度 | | ❌ 使用门槛高 | 初学者可能难以理解其抽象层次和结构 | | ❌ 不适合简单对象 | 如果对象很简单,使用建造者反而增加复杂度 | # 六、结构型模式 ## 1.适配器模式 适配器模式(Adapter Pattern)是设计模式中的一种**结构型模式**,它的主要作用是**让不兼容的接口可以协同工作**。它在不修改原有代码的基础上,通过引入一个“适配器”来转换接口,从而实现类之间的协作。 ### 核心思想 - **目标接口(Target)**:客户端所期望使用的接口。 - **被适配者(Adaptee)**:已经存在的类,但其接口与目标接口不兼容。 - **适配器(Adapter)**:实现目标接口,并持有被适配者的实例,负责将 Adaptee 的功能适配为目标接口的形式。 ### 适配器模式的类型 1. **类适配器(Class Adapter)** - 使用继承方式实现适配。 - 优点:可以在适配器中重写部分方法。 - 缺点:由于 Java 等语言不支持多重继承,只能适配单个类。 2. **对象适配器(Object Adapter)** - 使用组合方式实现适配。 - 更加灵活,推荐使用的方式。 3. **接口适配器** ![01适配器模式.png](img/03structural/01适配器模式.png) ### 适用场景 | 场景 | 描述 | | :------------- | :----------------------------------------------- | | 第三方库集成 | 当你希望复用现有类,但它的接口不符合你的需求时。 | | 接口兼容性问题 | 已有系统升级时,旧接口需要适配新接口。 | | 多数据源处理 | 不同数据格式或协议之间转换,比如 JSON 转 XML。 | ### 示例代码 假设有一个老系统 `LegacySystem` 提供了 `legacyOperation()` 方法,现在你希望它能符合新的 `ModernService` 接口中的 `operate()` 方法。 定义目标接口: ```java public interface ModernService { void operate(); } ``` 实现适配器: ```java public class LegacySystemAdapter implements ModernService { private LegacySystem legacySystem; public LegacySystemAdapter(LegacySystem legacySystem) { this.legacySystem = legacySystem; } @Override public void operate() { legacySystem.legacyOperation(); } } ``` 使用示例: ```java LegacySystem legacy = new LegacySystem(); ModernService service = new LegacySystemAdapter(legacy); service.operate(); // 适配调用 ``` ### 优缺点 | 优点 | 缺点 | | :------------------------------- | :------------------------------- | | 提高类的复用性,无需修改已有代码 | 增加系统的复杂度 | | 符合开闭原则 | 过度使用可能导致类爆炸 | | 解耦目标接口和被适配者 | 若接口变化频繁,维护成本可能上升 | 适配器模式是一种非常实用的设计模式,尤其适用于遗留系统整合、第三方服务接入、多系统对接等场景。它通过封装接口差异,实现了系统的解耦和扩展性提升。 ### SpringMVC中的适配器模式 在 **Spring MVC** 框架中,适配器模式被广泛应用,尤其是在处理控制器(Controller)与请求的适配过程中。它的核心是 **`HandlerAdapter` 接口**,用于统一不同类型的控制器(如 `@RequestMapping` 注解类、`SimpleControllerHandlerAdapter` 等)的调用方式。 主要作用: - 将不同形式的控制器(Controller)统一适配成可以处理 HTTP 请求的对象。 - 屏蔽底层实现差异,使框架更具扩展性和灵活性。 核心接口和类: **`HandlerAdapter` 接口(适配器接口)** ```java public interface HandlerAdapter { boolean supports(Object handler); ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception; } ``` - `supports()`:判断当前适配器是否支持该处理器(Controller)。 - `handle()`:执行实际的请求处理逻辑。 **常见的 `HandlerAdapter` 实现类** | 适配器类名 | 说明 | | :------------------------------- | :------------------------------------------------ | | `RequestMappingHandlerAdapter` | 最常用,用于适配使用 `@RequestMapping` 注解的方法 | | `SimpleControllerHandlerAdapter` | 用于适配实现 `Controller` 接口的传统控制器 | | `HttpRequestHandlerAdapter` | 用于适配实现 `HttpRequestHandler` 接口的处理器 | | `SimpleServletHandlerAdapter` | 用于适配传统 Servlet 的适配器 | 工作流程图 ![01适配器模式HandlerAdapter时序图.png](img/03structural/01适配器模式HandlerAdapter时序图.png) 类图 ![01适配器模式HandlerAdapter类图.png](img/03structural/01适配器模式HandlerAdapter类图.png) `SimpleControllerHandlerAdapter` ```java public class SimpleControllerHandlerAdapter implements HandlerAdapter { public boolean supports(Object handler) { return (handler instanceof Controller); } public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { return ((Controller) handler).handleRequest(request, response); } } ``` ## 2.桥接模式 ### 核心思想 桥接模式是一种结构型设计模式,它将抽象部分与实现部分分离,使它们可以独立变化。桥接模式通过组合代替继承,解决了类爆炸问题,让抽象和实现可以在各自的维度上扩展。 ### 核心概念 - **抽象部分(Abstraction)**:定义抽象接口,维护一个指向实现部分的引用 - **细化抽象(Refined Abstraction)**:扩展抽象部分,提供更具体的实现 - **实现部分(Implementor)**:定义实现接口 - **具体实现(Concrete Implementor)**:实现Implementor接口的具体类 ![02桥接模式.png](img/03structural/02桥接模式.png) ### 适用场景 1. **不希望在抽象和实现之间形成固定的绑定关系** 2. **抽象和实现部分都可能通过子类进行扩展** 3. **对抽象的实现进行修改不会影响客户端代码** 4. **想在多个对象间共享实现,但同时要求客户端不知道这一点** 5. **想通过继承和组合的方式,获得运行时的动态绑定能力** ### 示例代码 #### 1. 经典示例:图形绘制系统 ```java // 实现部分接口 interface DrawingAPI { void drawCircle(double x, double y, double radius); void drawRectangle(double x, double y, double width, double height); } // 具体实现1:Windows绘制API class WindowsDrawingAPI implements DrawingAPI { @Override public void drawCircle(double x, double y, double radius) { System.out.println("Windows API: 绘制圆形 (" + x + ", " + y + ") 半径: " + radius); } @Override public void drawRectangle(double x, double y, double width, double height) { System.out.println("Windows API: 绘制矩形 (" + x + ", " + y + ") 宽: " + width + " 高: " + height); } } // 具体实现2:Linux绘制API class LinuxDrawingAPI implements DrawingAPI { @Override public void drawCircle(double x, double y, double radius) { System.out.println("Linux API: 绘制圆形 (" + x + ", " + y + ") 半径: " + radius); } @Override public void drawRectangle(double x, double y, double width, double height) { System.out.println("Linux API: 绘制矩形 (" + x + ", " + y + ") 宽: " + width + " 高: " + height); } } // 具体实现3:Mac绘制API class MacDrawingAPI implements DrawingAPI { @Override public void drawCircle(double x, double y, double radius) { System.out.println("Mac API: 绘制圆形 (" + x + ", " + y + ") 半径: " + radius); } @Override public void drawRectangle(double x, double y, double width, double height) { System.out.println("Mac API: 绘制矩形 (" + x + ", " + y + ") 宽: " + width + " 高: " + height); } } // 抽象部分 abstract class Shape { protected DrawingAPI drawingAPI; public Shape(DrawingAPI drawingAPI) { this.drawingAPI = drawingAPI; } public abstract void draw(); public abstract void resize(double factor); } // 细化抽象1:圆形 class Circle extends Shape { private double x, y, radius; public Circle(double x, double y, double radius, DrawingAPI drawingAPI) { super(drawingAPI); this.x = x; this.y = y; this.radius = radius; } @Override public void draw() { drawingAPI.drawCircle(x, y, radius); } @Override public void resize(double factor) { radius *= factor; } public double getRadius() { return radius; } } // 细化抽象2:矩形 class Rectangle extends Shape { private double x, y, width, height; public Rectangle(double x, double y, double width, double height, DrawingAPI drawingAPI) { super(drawingAPI); this.x = x; this.y = y; this.width = width; this.height = height; } @Override public void draw() { drawingAPI.drawRectangle(x, y, width, height); } @Override public void resize(double factor) { width *= factor; height *= factor; } public double getWidth() { return width; } public double getHeight() { return height; } } // 客户端代码 public class BridgePatternDemo { public static void main(String[] args) { // 在Windows系统上绘制图形 DrawingAPI windowsAPI = new WindowsDrawingAPI(); Shape circle1 = new Circle(10, 10, 5, windowsAPI); Shape rectangle1 = new Rectangle(5, 5, 20, 15, windowsAPI); System.out.println("=== Windows系统图形绘制 ==="); circle1.draw(); rectangle1.draw(); // 在Linux系统上绘制图形 DrawingAPI linuxAPI = new LinuxDrawingAPI(); Shape circle2 = new Circle(15, 15, 8, linuxAPI); Shape rectangle2 = new Rectangle(10, 10, 25, 20, linuxAPI); System.out.println("\n=== Linux系统图形绘制 ==="); circle2.draw(); rectangle2.draw(); // 动态改变图形大小 System.out.println("\n=== 图形缩放示例 ==="); circle1.resize(1.5); circle1.draw(); rectangle2.resize(0.8); rectangle2.draw(); } } ``` #### 2. 实际应用示例:消息发送系统 ```java // 实现部分:消息发送接口 interface MessageSender { void sendMessage(String message, String recipient); } // 具体实现1:邮件发送 class EmailSender implements MessageSender { @Override public void sendMessage(String message, String recipient) { System.out.println("通过邮件发送给 " + recipient + ": " + message); } } // 具体实现2:短信发送 class SMSSender implements MessageSender { @Override public void sendMessage(String message, String recipient) { System.out.println("通过短信发送给 " + recipient + ": " + message); } } // 具体实现3:微信发送 class WeChatSender implements MessageSender { @Override public void sendMessage(String message, String recipient) { System.out.println("通过微信发送给 " + recipient + ": " + message); } } // 抽象部分:消息 abstract class Message { protected MessageSender sender; public Message(MessageSender sender) { this.sender = sender; } public abstract void send(String message, String recipient); // 设置发送器(运行时切换) public void setMessageSender(MessageSender sender) { this.sender = sender; } } // 细化抽象1:普通消息 class NormalMessage extends Message { public NormalMessage(MessageSender sender) { super(sender); } @Override public void send(String message, String recipient) { sender.sendMessage(message, recipient); } } // 细化抽象2:紧急消息 class UrgentMessage extends Message { public UrgentMessage(MessageSender sender) { super(sender); } @Override public void send(String message, String recipient) { String urgentMessage = "[紧急] " + message; sender.sendMessage(urgentMessage, recipient); } } // 细化抽象3:加密消息 class EncryptedMessage extends Message { public EncryptedMessage(MessageSender sender) { super(sender); } @Override public void send(String message, String recipient) { String encryptedMessage = encrypt(message); sender.sendMessage(encryptedMessage, recipient); } private String encrypt(String message) { // 简单的加密示例 StringBuilder encrypted = new StringBuilder(); for (char c : message.toCharArray()) { encrypted.append((char)(c + 1)); } return encrypted.toString(); } } // 客户端代码 public class MessageSystemDemo { public static void main(String[] args) { // 创建不同的发送器 MessageSender emailSender = new EmailSender(); MessageSender smsSender = new SMSSender(); MessageSender wechatSender = new WeChatSender(); // 创建不同类型的消息 Message normalMessage = new NormalMessage(emailSender); Message urgentMessage = new UrgentMessage(smsSender); Message encryptedMessage = new EncryptedMessage(wechatSender); System.out.println("=== 消息发送系统演示 ==="); // 发送普通消息 normalMessage.send("这是一条普通消息", "user@example.com"); // 发送紧急消息 urgentMessage.send("系统出现故障,请立即处理", "admin@company.com"); // 发送加密消息 encryptedMessage.send("这是一条机密信息", "security@company.com"); // 动态切换发送方式 System.out.println("\n=== 动态切换发送方式 ==="); normalMessage.setMessageSender(smsSender); normalMessage.send("这条消息改为短信发送", "user@mobile.com"); } } ``` #### 3. JDBC桥接模式示例 ```java // 模拟JDBC的桥接模式实现 // 实现部分:数据库驱动接口 interface DatabaseDriver { void connect(String url, String username, String password); void executeQuery(String sql); void close(); } // 具体实现1:MySQL驱动 class MySQLDriver implements DatabaseDriver { @Override public void connect(String url, String username, String password) { System.out.println("MySQL驱动连接到: " + url + " 用户: " + username); } @Override public void executeQuery(String sql) { System.out.println("MySQL执行查询: " + sql); } @Override public void close() { System.out.println("关闭MySQL连接"); } } // 具体实现2:PostgreSQL驱动 class PostgreSQLDriver implements DatabaseDriver { @Override public void connect(String url, String username, String password) { System.out.println("PostgreSQL驱动连接到: " + url + " 用户: " + username); } @Override public void executeQuery(String sql) { System.out.println("PostgreSQL执行查询: " + sql); } @Override public void close() { System.out.println("关闭PostgreSQL连接"); } } // 抽象部分:数据库连接 abstract class DatabaseConnection { protected DatabaseDriver driver; protected String url; protected String username; protected String password; public DatabaseConnection(DatabaseDriver driver, String url, String username, String password) { this.driver = driver; this.url = url; this.username = username; this.password = password; } public void connect() { driver.connect(url, username, password); } public abstract void executeQuery(String sql); public void close() { driver.close(); } } // 细化抽象:普通连接 class StandardConnection extends DatabaseConnection { public StandardConnection(DatabaseDriver driver, String url, String username, String password) { super(driver, url, username, password); } @Override public void executeQuery(String sql) { System.out.println("标准连接执行查询"); driver.executeQuery(sql); } } // 细化抽象:连接池连接 class PooledConnection extends DatabaseConnection { public PooledConnection(DatabaseDriver driver, String url, String username, String password) { super(driver, url, username, password); } @Override public void executeQuery(String sql) { System.out.println("连接池连接执行查询"); driver.executeQuery(sql); } @Override public void close() { System.out.println("连接池连接返回到池中,不实际关闭"); } } // 客户端代码 public class JDBCBridgeDemo { public static void main(String[] args) { System.out.println("=== JDBC桥接模式演示 ==="); // MySQL数据库连接 DatabaseDriver mysqlDriver = new MySQLDriver(); DatabaseConnection mysqlConnection = new StandardConnection( mysqlDriver, "jdbc:mysql://localhost:3306/test", "user", "password"); mysqlConnection.connect(); mysqlConnection.executeQuery("SELECT * FROM users"); mysqlConnection.close(); System.out.println(); // PostgreSQL数据库连接(使用连接池) DatabaseDriver postgresqlDriver = new PostgreSQLDriver(); DatabaseConnection postgresqlConnection = new PooledConnection( postgresqlDriver, "jdbc:postgresql://localhost:5432/test", "user", "password"); postgresqlConnection.connect(); postgresqlConnection.executeQuery("SELECT * FROM products"); postgresqlConnection.close(); } } ``` ### 优缺点 优点 1. **分离抽象和实现**:抽象和实现可以独立扩展,互不影响 2. **提高可扩展性**:可以在两个维度上独立扩展类层次 3. **隐藏实现细节**:客户端不需要知道实现的具体细节 4. **支持动态切换**:可以在运行时切换不同的实现 5. **符合开闭原则**:对扩展开放,对修改封闭 6. **减少子类数量**:避免了类爆炸问题 缺点 1. **增加系统复杂度**:引入了更多的类和接口,增加了系统理解难度 2. **性能开销**:通过委托调用实现,可能比直接继承有轻微的性能开销 3. **设计难度**:需要在设计阶段就识别出抽象和实现两个独立变化的维度 ### 与其他模式的关系 1. **与适配器模式**:桥接模式在设计阶段使用,适配器模式在已有接口不兼容时使用 2. **与装饰器模式**:装饰器模式扩展对象功能,桥接模式分离抽象和实现 3. **与策略模式**:策略模式定义算法族,桥接模式分离抽象和实现 ### 实际应用场景 1. **跨平台GUI框架**:如AWT中的组件和平台实现 2. **数据库驱动**:JDBC中Connection接口和不同数据库的实现 3. **设备控制**:遥控器和不同品牌的设备 4. **图形绘制**:不同操作系统上的图形绘制API 5. **消息系统**:不同类型的消息和不同的发送方式 6. **游戏开发**:游戏逻辑和不同平台的渲染实现 ## 装饰器模式 ### 核心思想 装饰器模式是一种结构型设计模式,它允许在不修改原有对象结构的情况下,动态地给对象添加新的功能。装饰器模式通过创建一个包装对象(装饰器)来包裹真实的对象,从而在运行时扩展对象的功能。 ### 核心概念 - **组件(Component)**:定义一个对象接口,可以给这些对象动态地添加职责 - **具体组件(Concrete Component)**:定义一个具体的对象,也可以给这个对象添加一些职责 - **装饰器(Decorator)**:维持一个指向Component对象的引用,并定义一个与Component接口一致的接口 - **具体装饰器(Concrete Decorator)**:向组件添加职责 ![03装饰器模式.png](img/03structural/03装饰器模式.png) ------------------------------------------------------- ![03装饰器模式咖啡订单.png](img/03structural/03装饰器模式咖啡订单.png) ### 适用场景 1. **需要扩展一个类的功能或给一个类添加附加职责** 2. **需要动态地给一个对象添加功能,这些功能也可以动态地被撤销** 3. **不能采用继承的方式对系统进行扩展或者采用继承不利于系统扩展和维护** 4. **需要为一批兄弟类进行改装或加装功能** 5. **在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责** ### 示例代码 #### 1. 经典示例:咖啡店订单系统 ```java // 组件接口 interface Coffee { String getDescription(); double getCost(); } // 具体组件:基础咖啡 class SimpleCoffee implements Coffee { @Override public String getDescription() { return "简单咖啡"; } @Override public double getCost() { return 2.0; } } // 装饰器基类 abstract class CoffeeDecorator implements Coffee { protected Coffee coffee; public CoffeeDecorator(Coffee coffee) { this.coffee = coffee; } @Override public String getDescription() { return coffee.getDescription(); } @Override public double getCost() { return coffee.getCost(); } } // 具体装饰器1:牛奶 class MilkDecorator extends CoffeeDecorator { public MilkDecorator(Coffee coffee) { super(coffee); } @Override public String getDescription() { return coffee.getDescription() + ", 牛奶"; } @Override public double getCost() { return coffee.getCost() + 0.5; } } // 具体装饰器2:糖 class SugarDecorator extends CoffeeDecorator { public SugarDecorator(Coffee coffee) { super(coffee); } @Override public String getDescription() { return coffee.getDescription() + ", 糖"; } @Override public double getCost() { return coffee.getCost() + 0.2; } } // 具体装饰器3:巧克力 class ChocolateDecorator extends CoffeeDecorator { public ChocolateDecorator(Coffee coffee) { super(coffee); } @Override public String getDescription() { return coffee.getDescription() + ", 巧克力"; } @Override public double getCost() { return coffee.getCost() + 0.8; } } // 具体装饰器4:奶泡 class WhipDecorator extends CoffeeDecorator { public WhipDecorator(Coffee coffee) { super(coffee); } @Override public String getDescription() { return coffee.getDescription() + ", 奶泡"; } @Override public double getCost() { return coffee.getCost() + 0.7; } } // 客户端代码 public class CoffeeShopDemo { public static void main(String[] args) { System.out.println("=== 咖啡店装饰器模式演示 ==="); // 基础咖啡 Coffee coffee = new SimpleCoffee(); System.out.println("基础咖啡: " + coffee.getDescription() + " - $" + coffee.getCost()); // 添加牛奶 coffee = new MilkDecorator(coffee); System.out.println("加牛奶: " + coffee.getDescription() + " - $" + coffee.getCost()); // 添加糖 coffee = new SugarDecorator(coffee); System.out.println("加糖: " + coffee.getDescription() + " - $" + coffee.getCost()); // 添加巧克力 coffee = new ChocolateDecorator(coffee); System.out.println("加巧克力: " + coffee.getDescription() + " - $" + coffee.getCost()); // 添加奶泡 coffee = new WhipDecorator(coffee); System.out.println("加奶泡: " + coffee.getDescription() + " - $" + coffee.getCost()); System.out.println("\n最终订单: " + coffee.getDescription() + " - 总价: $" + coffee.getCost()); // 另一个订单示例 System.out.println("\n=== 另一个订单示例 ==="); Coffee anotherCoffee = new SimpleCoffee(); anotherCoffee = new MilkDecorator(new ChocolateDecorator(new WhipDecorator(anotherCoffee))); System.out.println("定制咖啡: " + anotherCoffee.getDescription() + " - $" + anotherCoffee.getCost()); } } ``` #### 2. 实际应用示例:文本处理系统 ```java // 组件接口 interface TextProcessor { String process(String text); } // 具体组件:基础文本处理器 class BasicTextProcessor implements TextProcessor { @Override public String process(String text) { return text; } } // 装饰器基类 abstract class TextProcessorDecorator implements TextProcessor { protected TextProcessor processor; public TextProcessorDecorator(TextProcessor processor) { this.processor = processor; } @Override public String process(String text) { return processor.process(text); } } // 具体装饰器1:转换为大写 class UpperCaseDecorator extends TextProcessorDecorator { public UpperCaseDecorator(TextProcessor processor) { super(processor); } @Override public String process(String text) { return super.process(text).toUpperCase(); } } // 具体装饰器2:添加前缀 class PrefixDecorator extends TextProcessorDecorator { private String prefix; public PrefixDecorator(TextProcessor processor, String prefix) { super(processor); this.prefix = prefix; } @Override public String process(String text) { return prefix + super.process(text); } } // 具体装饰器3:添加后缀 class SuffixDecorator extends TextProcessorDecorator { private String suffix; public SuffixDecorator(TextProcessor processor, String suffix) { super(processor); this.suffix = suffix; } @Override public String process(String text) { return super.process(text) + suffix; } } // 具体装饰器4:去除空格 class TrimDecorator extends TextProcessorDecorator { public TrimDecorator(TextProcessor processor) { super(processor); } @Override public String process(String text) { return super.process(text).trim(); } } // 具体装饰器5:反转文本 class ReverseDecorator extends TextProcessorDecorator { public ReverseDecorator(TextProcessor processor) { super(processor); } @Override public String process(String text) { StringBuilder sb = new StringBuilder(super.process(text)); return sb.reverse().toString(); } } // 客户端代码 public class TextProcessingDemo { public static void main(String[] args) { System.out.println("=== 文本处理装饰器模式演示 ==="); String text = " hello world "; System.out.println("原始文本: '" + text + "'"); // 基础处理 TextProcessor processor = new BasicTextProcessor(); System.out.println("基础处理: '" + processor.process(text) + "'"); // 去除空格 processor = new TrimDecorator(processor); System.out.println("去除空格: '" + processor.process(text) + "'"); // 转换为大写 processor = new UpperCaseDecorator(processor); System.out.println("转换大写: '" + processor.process(text) + "'"); // 添加前缀和后缀 processor = new PrefixDecorator(processor, "[START] "); processor = new SuffixDecorator(processor, " [END]"); System.out.println("添加前缀后缀: '" + processor.process(text) + "'"); System.out.println("\n=== 复杂文本处理示例 ==="); String complexText = " java design patterns "; System.out.println("原始文本: '" + complexText + "'"); // 链式处理 TextProcessor complexProcessor = new SuffixDecorator( new PrefixDecorator( new UpperCaseDecorator( new TrimDecorator( new ReverseDecorator(new BasicTextProcessor()) ) ), "REVERSED: " ), " - PROCESSED" ); System.out.println("复杂处理: '" + complexProcessor.process(complexText) + "'"); } } ``` #### 3. 实际应用示例:文件读写装饰器 ```java import java.io.*; // 组件接口 interface DataReader { String read(); } // 具体组件:文件读取器 class FileReader implements DataReader { private String filename; public FileReader(String filename) { this.filename = filename; } @Override public String read() { // 模拟文件读取 return "文件内容: 这是文件 " + filename + " 的内容"; } } // 装饰器基类 abstract class DataReaderDecorator implements DataReader { protected DataReader reader; public DataReaderDecorator(DataReader reader) { this.reader = reader; } @Override public String read() { return reader.read(); } } // 具体装饰器1:解密装饰器 class DecryptionDecorator extends DataReaderDecorator { public DecryptionDecorator(DataReader reader) { super(reader); } @Override public String read() { String data = super.read(); return decrypt(data); } private String decrypt(String data) { // 简单解密示例 return data.replace("加密:", "解密:"); } } // 具体装饰器2:解压缩装饰器 class DecompressionDecorator extends DataReaderDecorator { public DecompressionDecorator(DataReader reader) { super(reader); } @Override public String read() { String data = super.read(); return decompress(data); } private String decompress(String data) { // 简单解压缩示例 return data.replace("压缩:", "解压:"); } } // 具体装饰器3:缓存装饰器 class CacheDecorator extends DataReaderDecorator { private String cachedData; private boolean isCached = false; public CacheDecorator(DataReader reader) { super(reader); } @Override public String read() { if (!isCached) { cachedData = super.read(); isCached = true; System.out.println("从源读取数据并缓存"); } else { System.out.println("从缓存读取数据"); } return cachedData; } } // 具体装饰器4:日志装饰器 class LoggingDecorator extends DataReaderDecorator { public LoggingDecorator(DataReader reader) { super(reader); } @Override public String read() { System.out.println("开始读取数据..."); String data = super.read(); System.out.println("数据读取完成: " + data); return data; } } // 客户端代码 public class FileReadingDemo { public static void main(String[] args) { System.out.println("=== 文件读取装饰器模式演示 ==="); // 基础文件读取 DataReader reader = new FileReader("data.txt"); System.out.println("基础读取: " + reader.read()); System.out.println("\n=== 添加缓存功能 ==="); DataReader cachedReader = new CacheDecorator(new FileReader("data.txt")); System.out.println("第一次读取: " + cachedReader.read()); System.out.println("第二次读取: " + cachedReader.read()); System.out.println("第三次读取: " + cachedReader.read()); System.out.println("\n=== 添加日志功能 ==="); DataReader loggedReader = new LoggingDecorator(new FileReader("data.txt")); System.out.println("读取结果: " + loggedReader.read()); System.out.println("\n=== 组合多种功能 ==="); DataReader complexReader = new LoggingDecorator( new CacheDecorator( new DecompressionDecorator( new DecryptionDecorator( new FileReader("encrypted_data.txt") ) ) ) ); System.out.println("复杂处理结果: " + complexReader.read()); System.out.println("再次读取: " + complexReader.read()); } } ``` #### 4. Java I/O流中的装饰器模式 ```java import java.io.*; // 演示Java标准库中的装饰器模式 public class JavaIODemo { public static void main(String[] args) { System.out.println("=== Java I/O中的装饰器模式 ==="); try { // 基础组件:文件输入流 FileInputStream fileInputStream = new FileInputStream("example.txt"); // 装饰器1:缓冲流 BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream); // 装饰器2:数据输入流 DataInputStream dataInputStream = new DataInputStream(bufferedInputStream); // 装饰器3:对象输入流 ObjectInputStream objectInputStream = new ObjectInputStream(dataInputStream); System.out.println("创建了多层装饰的输入流"); // 关闭最外层流,会自动关闭内层流 objectInputStream.close(); System.out.println("\n=== 输出流装饰器示例 ==="); // 输出流装饰器示例 FileOutputStream fileOutputStream = new FileOutputStream("output.txt"); BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream); DataOutputStream dataOutputStream = new DataOutputStream(bufferedOutputStream); PrintWriter printWriter = new PrintWriter(dataOutputStream); printWriter.println("这是通过装饰器模式处理的输出"); printWriter.close(); // 关闭最外层流 } catch (Exception e) { e.printStackTrace(); } } } ``` ### 优缺点 #### 优点 1. **灵活性高**:可以在运行时动态地添加或删除功能 2. **符合开闭原则**:无需修改现有代码即可扩展功能 3. **避免类爆炸**:相比继承,装饰器模式避免了子类数量的指数级增长 4. **职责分离**:每个装饰器只关注自己的功能,符合单一职责原则 5. **可组合性**:可以将多个装饰器组合使用,创建复杂的功能 6. **透明性**:装饰器和被装饰对象具有相同的接口,客户端使用透明 #### 缺点 1. **增加系统复杂度**:引入了多个类,增加了系统理解和维护的难度 2. **调试困难**:多个装饰器嵌套时,调试和排查问题比较困难 3. **性能开销**:多层装饰会产生额外的方法调用开销 4. **容易出错**:装饰器的顺序可能影响最终结果,容易出错 5. **对象识别问题**:装饰后的对象类型发生变化,可能影响类型检查 ### 与其他模式的关系 1. **与适配器模式**:适配器模式改变接口,装饰器模式扩展功能 2. **与代理模式**:代理模式控制对对象的访问,装饰器模式扩展对象功能 3. **与策略模式**:策略模式改变算法,装饰器模式添加职责 4. **与组合模式**:组合模式处理树形结构,装饰器模式处理链式结构 ### 实际应用场景 1. **Java I/O流**:FileInputStream、BufferedInputStream、DataInputStream等 2. **Web开发**:HTTP请求/响应的过滤器和拦截器 3. **GUI组件**:Swing中的组件装饰 4. **日志系统**:不同级别的日志装饰器 5. **缓存系统**:多级缓存装饰器 6. **安全系统**:权限检查、加密解密装饰器 7. **性能监控**:计时、统计装饰器 8. **数据处理**:压缩、加密、格式化装饰器 装饰器模式通过动态组合的方式扩展对象功能,提供了比继承更灵活的解决方案,是面向对象设计中的重要模式之一。 ## 组合模式 ### 核心思想 组合模式是一种结构型设计模式,它将对象组合成树形结构以表示"部分-整体"的层次结构。组合模式使得客户端可以统一地处理单个对象和组合对象,无需关心处理的是叶子节点还是组合节点。 ### 核心概念 - **组件(Component)**:抽象类或接口,声明所有具体组件和组合对象的共同接口 - **叶子(Leaf)**:表示树形结构中的叶子节点,没有子节点 - **复合组件(Composite)**:表示树形结构中的分支节点,可以包含子组件 - **客户端(Client)**:通过组件接口操作对象,无需区分叶子节点和组合节点 ![04组合模式.png](img/03structural/04组合模式.png) ### 适用场景 1. **想表示对象的部分-整体层次结构** 2. **希望客户端忽略组合对象与单个对象的不同,统一地使用组合结构中的所有对象** 3. **对象结构是树形结构,如文件系统、菜单系统、组织架构等** 4. **需要动态地组合对象,形成树形结构** 5. **递归处理具有层级关系的数据结构** ### 示例代码 #### 1. 经典示例:文件系统 ```java import java.util.*; // 组件接口 abstract class FileSystemComponent { protected String name; public FileSystemComponent(String name) { this.name = name; } // 公共方法 public String getName() { return name; } // 抽象方法 - 子类必须实现 public abstract void display(String indent); public abstract long getSize(); public abstract int getCount(); // 默认实现 - 叶子节点通常不支持这些操作 public void add(FileSystemComponent component) { throw new UnsupportedOperationException("不支持添加操作"); } public void remove(FileSystemComponent component) { throw new UnsupportedOperationException("不支持删除操作"); } public FileSystemComponent getChild(int index) { throw new UnsupportedOperationException("不支持获取子节点操作"); } } // 叶子节点:文件 class File extends FileSystemComponent { private long size; public File(String name, long size) { super(name); this.size = size; } @Override public void display(String indent) { System.out.println(indent + "📄 " + name + " (" + size + " bytes)"); } @Override public long getSize() { return size; } @Override public int getCount() { return 1; // 文件计数为1 } } // 复合组件:目录 class Directory extends FileSystemComponent { private List children = new ArrayList<>(); public Directory(String name) { super(name); } @Override public void add(FileSystemComponent component) { children.add(component); } @Override public void remove(FileSystemComponent component) { children.remove(component); } @Override public FileSystemComponent getChild(int index) { return children.get(index); } @Override public void display(String indent) { System.out.println(indent + "📁 " + name + " (目录)"); for (FileSystemComponent child : children) { child.display(indent + " "); } } @Override public long getSize() { long totalSize = 0; for (FileSystemComponent child : children) { totalSize += child.getSize(); } return totalSize; } @Override public int getCount() { int totalCount = 1; // 目录本身计数为1 for (FileSystemComponent child : children) { totalCount += child.getCount(); } return totalCount; } public List getChildren() { return new ArrayList<>(children); } } // 客户端代码 public class FileSystemDemo { public static void main(String[] args) { System.out.println("=== 文件系统组合模式演示 ==="); // 创建目录结构 Directory root = new Directory("根目录"); Directory documents = new Directory("文档"); Directory images = new Directory("图片"); Directory projects = new Directory("项目"); // 创建文件 File readme = new File("README.md", 1024); File config = new File("config.json", 512); File photo1 = new File("vacation.jpg", 2048000); File photo2 = new Directory("family.jpg", 1536000); File project1 = new File("project1.java", 8192); File project2 = new File("project2.java", 12288); // 构建目录树 root.add(documents); root.add(images); root.add(projects); root.add(readme); root.add(config); documents.add(new File("document1.txt", 2048)); documents.add(new File("document2.pdf", 4096)); images.add(photo1); images.add(photo2); projects.add(project1); projects.add(project2); // 显示文件系统结构 System.out.println("文件系统结构:"); root.display(""); System.out.println("\n统计信息:"); System.out.println("总大小: " + root.getSize() + " bytes"); System.out.println("总文件数: " + root.getCount()); System.out.println("文档目录大小: " + documents.getSize() + " bytes"); System.out.println("文档目录文件数: " + documents.getCount()); } } ``` #### 2. 实际应用示例:图形绘制系统 ```java import java.awt.*; import java.util.*; // 组件接口 abstract class Graphic { protected String name; public Graphic(String name) { this.name = name; } public String getName() { return name; } // 抽象方法 public abstract void draw(); public abstract void move(int x, int y); public abstract Rectangle getBounds(); // 默认实现 public void add(Graphic graphic) { throw new UnsupportedOperationException("不支持添加操作"); } public void remove(Graphic graphic) { throw new UnsupportedOperationException("不支持删除操作"); } public Graphic getChild(int index) { throw new UnsupportedOperationException("不支持获取子节点操作"); } } // 叶子节点:点 class Dot extends Graphic { private int x, y; private String color; public Dot(String name, int x, int y, String color) { super(name); this.x = x; this.y = y; this.color = color; } @Override public void draw() { System.out.println("绘制点: " + name + " 位置(" + x + "," + y + ") 颜色:" + color); } @Override public void move(int x, int y) { this.x += x; this.y += y; } @Override public Rectangle getBounds() { return new Rectangle(x, y, 1, 1); } public int getX() { return x; } public int getY() { return y; } public String getColor() { return color; } } // 叶子节点:圆 class Circle extends Graphic { private int x, y, radius; private String color; public Circle(String name, int x, int y, int radius, String color) { super(name); this.x = x; this.y = y; this.radius = radius; this.color = color; } @Override public void draw() { System.out.println("绘制圆: " + name + " 中心(" + x + "," + y + ") 半径:" + radius + " 颜色:" + color); } @Override public void move(int x, int y) { this.x += x; this.y += y; } @Override public Rectangle getBounds() { return new Rectangle(x - radius, y - radius, radius * 2, radius * 2); } public int getX() { return x; } public int getY() { return y; } public int getRadius() { return radius; } public String getColor() { return color; } } // 复合组件:复合图形 class CompoundGraphic extends Graphic { private List children = new ArrayList<>(); public CompoundGraphic(String name) { super(name); } @Override public void add(Graphic graphic) { children.add(graphic); } @Override public void remove(Graphic graphic) { children.remove(graphic); } @Override public Graphic getChild(int index) { return children.get(index); } @Override public void draw() { System.out.println("绘制复合图形: " + name); for (Graphic child : children) { child.draw(); } } @Override public void move(int x, int y) { for (Graphic child : children) { child.move(x, y); } } @Override public Rectangle getBounds() { if (children.isEmpty()) { return new Rectangle(0, 0, 0, 0); } Rectangle bounds = children.get(0).getBounds(); for (int i = 1; i < children.size(); i++) { bounds = bounds.union(children.get(i).getBounds()); } return bounds; } public List getChildren() { return new ArrayList<>(children); } } // 客户端代码 public class GraphicsDemo { public static void main(String[] args) { System.out.println("=== 图形绘制组合模式演示 ==="); // 创建基本图形 Dot dot1 = new Dot("红点", 10, 20, "红色"); Dot dot2 = new Dot("蓝点", 30, 40, "蓝色"); Circle circle1 = new Circle("绿圆", 50, 60, 15, "绿色"); Circle circle2 = new Circle("黄圆", 80, 90, 20, "黄色"); // 创建复合图形 CompoundGraphic group1 = new CompoundGraphic("点组"); group1.add(dot1); group1.add(dot2); CompoundGraphic group2 = new CompoundGraphic("圆组"); group2.add(circle1); group2.add(circle2); // 创建更大的复合图形 CompoundGraphic allGraphics = new CompoundGraphic("所有图形"); allGraphics.add(group1); allGraphics.add(group2); allGraphics.add(new Dot("单独点", 100, 120, "紫色")); // 绘制所有图形 System.out.println("绘制所有图形:"); allGraphics.draw(); // 移动所有图形 System.out.println("\n移动所有图形 (x+5, y+5):"); allGraphics.move(5, 5); allGraphics.draw(); // 获取边界 System.out.println("\n边界信息:"); Rectangle bounds = allGraphics.getBounds(); System.out.println("整体边界: (" + bounds.x + "," + bounds.y + ") 宽:" + bounds.width + " 高:" + bounds.height); } } ``` #### 3. 实际应用示例:菜单系统 ```java import java.util.*; // 组件接口 abstract class MenuComponent { protected String name; protected String description; public MenuComponent(String name, String description) { this.name = name; this.description = description; } public String getName() { return name; } public String getDescription() { return description; } // 抽象方法 public abstract void print(); public abstract double getPrice(); public abstract boolean isVegetarian(); // 默认实现 public void add(MenuComponent component) { throw new UnsupportedOperationException("不支持添加操作"); } public void remove(MenuComponent component) { throw new UnsupportedOperationException("不支持删除操作"); } public MenuComponent getChild(int index) { throw new UnsupportedOperationException("不支持获取子节点操作"); } } // 叶子节点:菜单项 class MenuItem extends MenuComponent { private double price; private boolean vegetarian; public MenuItem(String name, String description, boolean vegetarian, double price) { super(name, description); this.vegetarian = vegetarian; this.price = price; } @Override public void print() { System.out.print(" " + getName()); if (isVegetarian()) { System.out.print("(素食)"); } System.out.println(", 价格: $" + getPrice()); System.out.println(" -- " + getDescription()); } @Override public double getPrice() { return price; } @Override public boolean isVegetarian() { return vegetarian; } } // 复合组件:菜单 class Menu extends MenuComponent { private List menuComponents = new ArrayList<>(); public Menu(String name, String description) { super(name, description); } @Override public void add(MenuComponent component) { menuComponents.add(component); } @Override public void remove(MenuComponent component) { menuComponents.remove(component); } @Override public MenuComponent getChild(int index) { return menuComponents.get(index); } @Override public void print() { System.out.println("\n" + getName() + ", " + getDescription()); System.out.println("---------------------"); for (MenuComponent component : menuComponents) { component.print(); } } @Override public double getPrice() { double totalPrice = 0; for (MenuComponent component : menuComponents) { totalPrice += component.getPrice(); } return totalPrice; } @Override public boolean isVegetarian() { for (MenuComponent component : menuComponents) { if (!component.isVegetarian()) { return false; } } return true; } public List getMenuComponents() { return new ArrayList<>(menuComponents); } } // 客户端代码 public class MenuDemo { public static void main(String[] args) { System.out.println("=== 餐厅菜单组合模式演示 ==="); // 创建菜单结构 MenuComponent pancakeHouseMenu = new Menu("煎饼屋菜单", "早餐"); MenuComponent dinerMenu = new Menu("餐厅菜单", "午餐"); MenuComponent cafeMenu = new Menu("咖啡厅菜单", "晚餐"); MenuComponent dessertMenu = new Menu("甜品菜单", "甜点"); // 添加菜单项到煎饼屋菜单 pancakeHouseMenu.add(new MenuItem("K&B煎饼早餐", "薄煎饼配炒蛋和吐司", true, 2.99)); pancakeHouseMenu.add(new MenuItem("常规煎饼早餐", "薄煎饼配炒蛋和香肠", false, 2.99)); pancakeHouseMenu.add(new MenuItem("蓝莓煎饼", "新鲜蓝莓制作的煎饼", true, 3.49)); pancakeHouseMenu.add(new MenuItem("华夫饼", "华夫饼配浆果和奶油", true, 3.59)); // 添加菜单项到餐厅菜单 dinerMenu.add(new MenuItem("素食BLT", "(仿制)培根配生菜和番茄", true, 2.99)); dinerMenu.add(new MenuItem("BLT", "培根配生菜和番茄", false, 2.99)); dinerMenu.add(new MenuItem("汤", "今日汤品配沙拉", false, 3.29)); dinerMenu.add(new MenuItem("热狗", "热狗配酸菜、德国酸菜和薯条", false, 3.05)); // 添加菜单项到甜品菜单 dessertMenu.add(new MenuItem("苹果派", "苹果派配香草冰淇淋", true, 1.59)); dessertMenu.add(new MenuItem("芝士蛋糕", "纽约芝士蛋糕配蓝莓", true, 1.99)); dessertMenu.add(new MenuItem("巧克力慕斯", "巧克力慕斯蛋糕", true, 1.89)); // 添加菜单项到咖啡厅菜单 cafeMenu.add(new MenuItem("素食汉堡", "全麦面包配生菜、番茄和薯条", true, 3.99)); cafeMenu.add(new MenuItem("汉堡", "牛肉汉堡配生菜、番茄和薯条", false, 3.99)); cafeMenu.add(new MenuItem("咖啡", "现磨咖啡", true, 1.99)); cafeMenu.add(dessertMenu); // 添加甜品子菜单 // 创建主菜单 MenuComponent allMenus = new Menu("所有菜单", "所有餐厅菜单"); allMenus.add(pancakeHouseMenu); allMenus.add(dinerMenu); allMenus.add(cafeMenu); // 打印菜单 System.out.println("=== 完整菜单 ==="); allMenus.print(); // 统计信息 System.out.println("\n=== 菜单统计 ==="); System.out.println("总菜单价格: $" + String.format("%.2f", allMenus.getPrice())); System.out.println("是否全素食: " + (allMenus.isVegetarian() ? "是" : "否")); System.out.println("\n=== 甜品菜单详情 ==="); dessertMenu.print(); System.out.println("甜品菜单总价: $" + String.format("%.2f", dessertMenu.getPrice())); } } ``` ### 优缺点 #### 优点 1. **统一性**:客户端可以一致地处理单个对象和组合对象 2. **灵活性**:可以很容易地增加新的组件类型 3. **简化客户端代码**:客户端不需要区分叶子节点和组合节点 4. **符合开闭原则**:易于扩展新的组件类型 5. **层次结构清晰**:能够清晰地表示对象的层次结构 6. **递归遍历**:天然支持递归操作和遍历 #### 缺点 1. **设计复杂**:引入了多个类,增加了系统复杂度 2. **类型安全问题**:在某些情况下可能需要类型检查 3. **难以限制容器**:很难限制容器中组件的类型 4. **性能开销**:递归调用可能带来一定的性能开销 5. **调试困难**:复杂的组合结构可能难以调试 ### 与其他模式的关系 1. **与装饰器模式**:组合模式组织对象,装饰器模式扩展功能 2. **与访问者模式**:访问者模式可以遍历组合结构中的对象 3. **与迭代器模式**:可以为组合结构提供迭代器 4. **与责任链模式**:两者都处理对象链,但目的不同 ### 实际应用场景 1. **文件系统**:目录和文件的层次结构 2. **GUI组件**:窗口、面板、按钮等组件的层次结构 3. **菜单系统**:菜单和菜单项的层次结构 4. **组织架构**:部门和员工的层次结构 5. **XML/HTML解析**:DOM树结构 6. **游戏对象**:场景、组、对象的层次结构 7. **配置管理**:配置项的层次结构 8. **表达式解析**:算术表达式的树形结构 组合模式通过将对象组织成树形结构,使得复杂的层次关系变得简单易处理,是处理"部分-整体"关系的重要设计模式。 ## 外观模式 ### 核心思想 外观模式是一种结构型设计模式,它为复杂的子系统提供一个简化的统一接口。外观模式通过创建一个外观类来隐藏复杂子系统的复杂性,使得客户端可以更容易地使用这些子系统。 ### 核心概念 - **外观(Facade)**:提供简化的接口访问复杂子系统 - **子系统(Subsystem)**:实现具体功能的类集合,不直接被客户端访问 - **客户端(Client)**:通过外观接口使用子系统功能 ![05外观模式.png](img/03structural/05外观模式.png) ### 适用场景 1. **为复杂的子系统提供简单的接口** 2. **客户程序与抽象类的实现部分之间存在很大的依赖性** 3. **需要构建层次化的子系统时,使用外观模式定义子系统中每层的入口点** 4. **想要让子系统之间相互独立,甚至不可知** 5. **需要将子系统组织为多层结构时** ### 示例代码 #### 1. 经典示例:家庭影院系统 ![05外观模式家庭影院.png](img/03structural/05外观模式家庭影院.png) ```java // 子系统1:DVD播放器 class DVDPlayer { private static DVDPlayer instance = new DVDPlayer(); private DVDPlayer() {} public static DVDPlayer getInstance() { return instance; } public void on() { System.out.println("DVD播放器已开启"); } public void off() { System.out.println("DVD播放器已关闭"); } public void play(String movie) { System.out.println("正在播放电影: " + movie); } public void stop() { System.out.println("停止播放电影"); } public void eject() { System.out.println("弹出DVD光盘"); } public void pause() { System.out.println("暂停播放"); } } // 子系统2:投影仪 class Projector { private static Projector instance = new Projector(); private Projector() {} public static Projector getInstance() { return instance; } public void on() { System.out.println("投影仪已开启"); } public void off() { System.out.println("投影仪已关闭"); } public void wideScreenMode() { System.out.println("投影仪设置为宽屏模式"); } public void tvMode() { System.out.println("投影仪设置为TV模式"); } } // 子系统3:音响系统 class Amplifier { private static Amplifier instance = new Amplifier(); private Amplifier() {} public static Amplifier getInstance() { return instance; } public void on() { System.out.println("音响放大器已开启"); } public void off() { System.out.println("音响放大器已关闭"); } public void setDVD() { System.out.println("音响输入源设置为DVD"); } public void setVolume(int level) { System.out.println("音响音量设置为: " + level); } public void setSurroundSound() { System.out.println("音响设置为环绕声模式"); } } // 子系统4:屏幕 class Screen { private static Screen instance = new Screen(); private Screen() {} public static Screen getInstance() { return instance; } public void up() { System.out.println("屏幕升起"); } public void down() { System.out.println("屏幕降下"); } } // 子系统5:灯光 class TheaterLights { private static TheaterLights instance = new TheaterLights(); private TheaterLights() {} public static TheaterLights getInstance() { return instance; } public void dim(int level) { System.out.println("灯光调暗到: " + level + "%"); } public void on() { System.out.println("灯光开启"); } public void off() { System.out.println("灯光关闭"); } } // 子系统6:爆米花机 class PopcornPopper { private static PopcornPopper instance = new PopcornPopper(); private PopcornPopper() {} public static PopcornPopper getInstance() { return instance; } public void on() { System.out.println("爆米花机开启"); } public void off() { System.out.println("爆米花机关闭"); } public void pop() { System.out.println("开始制作爆米花"); } } // 外观类:家庭影院外观 class HomeTheaterFacade { private Amplifier amp; private Tuner tuner; private DVDPlayer dvd; private Projector projector; private Screen screen; private TheaterLights lights; private PopcornPopper popcorn; public HomeTheaterFacade() { this.amp = Amplifier.getInstance(); this.dvd = DVDPlayer.getInstance(); this.projector = Projector.getInstance(); this.screen = Screen.getInstance(); this.lights = TheaterLights.getInstance(); this.popcorn = PopcornPopper.getInstance(); } // 简化的观看电影接口 public void watchMovie(String movie) { System.out.println("准备观看电影: " + movie); System.out.println("-------------------"); popcorn.on(); popcorn.pop(); lights.dim(10); screen.down(); projector.on(); projector.wideScreenMode(); amp.on(); amp.setDVD(); amp.setSurroundSound(); amp.setVolume(5); dvd.on(); dvd.play(movie); System.out.println("电影准备就绪,开始享受吧!\n"); } // 简化的结束观看接口 public void endMovie() { System.out.println("关闭家庭影院..."); System.out.println("-------------------"); popcorn.off(); lights.on(); screen.up(); projector.off(); amp.off(); dvd.stop(); dvd.eject(); dvd.off(); System.out.println("家庭影院已关闭\n"); } // 简化的听音乐接口 public void listenToMusic() { System.out.println("准备听音乐..."); System.out.println("-------------------"); lights.on(); amp.on(); amp.setVolume(7); System.out.println("音乐系统准备就绪\n"); } } // 客户端代码 public class HomeTheaterDemo { public static void main(String[] args) { System.out.println("=== 家庭影院外观模式演示 ==="); // 创建外观 HomeTheaterFacade homeTheater = new HomeTheaterFacade(); // 观看电影 - 简单接口 homeTheater.watchMovie("《阿凡达》"); // 模拟观看过程中的操作 System.out.println("观看中..."); DVDPlayer.getInstance().pause(); System.out.println("暂停一下...\n"); DVDPlayer.getInstance().play("《阿凡达》"); System.out.println("继续观看...\n"); // 结束观看 - 简单接口 homeTheater.endMovie(); // 听音乐 homeTheater.listenToMusic(); System.out.println("享受音乐时光...\n"); homeTheater.endMovie(); } } ``` #### 2. 实际应用示例:计算机启动系统 ![05外观模式计算机启动.png](img/03structural/05外观模式计算机启动.png) ```java // 子系统1:CPU class CPU { public void freeze() { System.out.println("CPU: 冻结处理器"); } public void jump(long position) { System.out.println("CPU: 跳转到位置 " + position); } public void execute() { System.out.println("CPU: 开始执行指令"); } public void shutdown() { System.out.println("CPU: 关闭处理器"); } } // 子系统2:内存 class Memory { public void load(long position, byte[] data) { System.out.println("内存: 在位置 " + position + " 加载数据 (" + data.length + " 字节)"); } public void shutdown() { System.out.println("内存: 关闭内存"); } } // 子系统3:硬盘 class HardDrive { public byte[] read(long lba, int size) { System.out.println("硬盘: 从LBA " + lba + " 读取 " + size + " 字节"); return new byte[size]; // 模拟读取的数据 } public void shutdown() { System.out.println("硬盘: 关闭硬盘"); } } // 子系统4:操作系统 class OperatingSystem { public void load() { System.out.println("操作系统: 加载操作系统内核"); } public void start() { System.out.println("操作系统: 启动系统服务"); } public void shutdown() { System.out.println("操作系统: 关闭系统服务"); } } // 子系统5:BIOS class BIOS { public void powerOn() { System.out.println("BIOS: 电源开启自检"); } public void hardwareCheck() { System.out.println("BIOS: 硬件自检完成"); } public void boot() { System.out.println("BIOS: 启动引导程序"); } public void powerOff() { System.out.println("BIOS: 电源关闭"); } } // 子系统6:网络 class Network { public void initialize() { System.out.println("网络: 初始化网络接口"); } public void connect() { System.out.println("网络: 连接网络"); } public void disconnect() { System.out.println("网络: 断开网络连接"); } public void shutdown() { System.out.println("网络: 关闭网络服务"); } } // 外观类:计算机外观 class ComputerFacade { private CPU cpu; private Memory memory; private HardDrive hardDrive; private OperatingSystem os; private BIOS bios; private Network network; public ComputerFacade() { this.cpu = new CPU(); this.memory = new Memory(); this.hardDrive = new HardDrive(); this.os = new OperatingSystem(); this.bios = new BIOS(); this.network = new Network(); } // 简化的开机接口 public void start() { System.out.println("=== 计算机启动过程 ==="); // BIOS启动 bios.powerOn(); bios.hardwareCheck(); bios.boot(); // 硬件初始化 cpu.freeze(); byte[] bootData = hardDrive.read(0, 1024); memory.load(0, bootData); cpu.jump(0); cpu.execute(); // 操作系统启动 os.load(); os.start(); // 网络初始化 network.initialize(); network.connect(); System.out.println("计算机启动完成!\n"); } // 简化的关机接口 public void shutdown() { System.out.println("=== 计算机关闭过程 ==="); // 网络断开 network.disconnect(); network.shutdown(); // 操作系统关闭 os.shutdown(); // 硬件关闭 cpu.shutdown(); memory.shutdown(); hardDrive.shutdown(); bios.powerOff(); System.out.println("计算机已关闭!\n"); } // 简化的重启接口 public void restart() { System.out.println("=== 计算机重启过程 ==="); shutdown(); start(); } } // 客户端代码 public class ComputerDemo { public static void main(String[] args) { System.out.println("=== 计算机启动外观模式演示 ==="); // 创建计算机外观 ComputerFacade computer = new ComputerFacade(); // 启动计算机 - 简单接口 computer.start(); System.out.println("使用计算机进行工作...\n"); // 重启计算机 - 简单接口 computer.restart(); System.out.println("继续使用计算机...\n"); // 关闭计算机 - 简单接口 computer.shutdown(); } } ``` #### 3. 实际应用示例:在线购物系统 ![05外观模式在线购物.png](img/03structural/05外观模式在线购物.png) ```java // 子系统1:库存管理 class InventoryService { public boolean checkStock(String productId, int quantity) { System.out.println("库存服务: 检查商品 " + productId + " 库存数量 " + quantity); // 模拟库存检查 boolean inStock = Math.random() > 0.1; // 90%有库存 System.out.println("库存检查结果: " + (inStock ? "有库存" : "缺货")); return inStock; } public void reserveStock(String productId, int quantity) { System.out.println("库存服务: 预留商品 " + productId + " 数量 " + quantity); } public void releaseStock(String productId, int quantity) { System.out.println("库存服务: 释放商品 " + productId + " 数量 " + quantity); } public void updateStock(String productId, int quantity) { System.out.println("库存服务: 更新商品 " + productId + " 库存为 " + quantity); } } // 子系统2:支付处理 class PaymentService { public boolean processPayment(String customerId, double amount) { System.out.println("支付服务: 处理客户 " + customerId + " 的支付,金额 $" + amount); // 模拟支付处理 boolean success = Math.random() > 0.05; // 95%支付成功 System.out.println("支付处理结果: " + (success ? "成功" : "失败")); return success; } public void refund(String transactionId, double amount) { System.out.println("支付服务: 处理交易 " + transactionId + " 的退款,金额 $" + amount); } public String getTransactionId() { return "TXN" + System.currentTimeMillis(); } } // 子系统3:订单管理 class OrderService { public String createOrder(String customerId, String productId, int quantity, double price) { System.out.println("订单服务: 创建订单 - 客户 " + customerId + ", 商品 " + productId + ", 数量 " + quantity + ", 单价 $" + price); String orderId = "ORD" + System.currentTimeMillis(); System.out.println("订单创建成功: " + orderId); return orderId; } public void updateOrderStatus(String orderId, String status) { System.out.println("订单服务: 更新订单 " + orderId + " 状态为 " + status); } public void cancelOrder(String orderId) { System.out.println("订单服务: 取消订单 " + orderId); } } // 子系统4:物流配送 class ShippingService { public String generateTrackingNumber(String orderId) { System.out.println("物流服务: 为订单 " + orderId + " 生成跟踪号"); String trackingNumber = "TRK" + System.currentTimeMillis(); System.out.println("跟踪号生成: " + trackingNumber); return trackingNumber; } public void scheduleShipment(String orderId, String address) { System.out.println("物流服务: 安排订单 " + orderId + " 发货到 " + address); } public void updateShipmentStatus(String trackingNumber, String status) { System.out.println("物流服务: 更新跟踪号 " + trackingNumber + " 状态为 " + status); } } // 子系统5:通知服务 class NotificationService { public void sendOrderConfirmation(String customerId, String orderId) { System.out.println("通知服务: 发送订单确认给客户 " + customerId + ",订单号 " + orderId); } public void sendShippingNotification(String customerId, String trackingNumber) { System.out.println("通知服务: 发送发货通知给客户 " + customerId + ",跟踪号 " + trackingNumber); } public void sendPaymentConfirmation(String customerId, String transactionId) { System.out.println("通知服务: 发送支付确认给客户 " + customerId + ",交易号 " + transactionId); } } // 子系统6:用户服务 class UserService { public String getCustomerAddress(String customerId) { System.out.println("用户服务: 获取客户 " + customerId + " 的地址"); return "北京市朝阳区xxx街道xxx号"; } public String getCustomerEmail(String customerId) { System.out.println("用户服务: 获取客户 " + customerId + " 的邮箱"); return customerId + "@example.com"; } } // 外观类:在线购物外观 class OnlineShoppingFacade { private InventoryService inventoryService; private PaymentService paymentService; private OrderService orderService; private ShippingService shippingService; private NotificationService notificationService; private UserService userService; public OnlineShoppingFacade() { this.inventoryService = new InventoryService(); this.paymentService = new PaymentService(); this.orderService = new OrderService(); this.shippingService = new ShippingService(); this.notificationService = new NotificationService(); this.userService = new UserService(); } // 简化的购买商品接口 public boolean purchaseProduct(String customerId, String productId, int quantity, double price) { System.out.println("=== 开始购买流程 ==="); System.out.println("客户: " + customerId + ", 商品: " + productId + ", 数量: " + quantity + ", 单价: $" + price); System.out.println("----------------------------------------"); // 1. 检查库存 if (!inventoryService.checkStock(productId, quantity)) { System.out.println("购买失败: 商品库存不足\n"); return false; } // 2. 预留库存 inventoryService.reserveStock(productId, quantity); // 3. 创建订单 String orderId = orderService.createOrder(customerId, productId, quantity, price); // 4. 处理支付 if (!paymentService.processPayment(customerId, price * quantity)) { System.out.println("购买失败: 支付处理失败"); inventoryService.releaseStock(productId, quantity); orderService.cancelOrder(orderId); System.out.println(); return false; } String transactionId = paymentService.getTransactionId(); // 5. 更新订单状态 orderService.updateOrderStatus(orderId, "已支付"); // 6. 减少库存 inventoryService.updateStock(productId, -quantity); // 7. 安排发货 String customerAddress = userService.getCustomerAddress(customerId); shippingService.scheduleShipment(orderId, customerAddress); String trackingNumber = shippingService.generateTrackingNumber(orderId); shippingService.updateShipmentStatus(trackingNumber, "已发货"); // 8. 发送通知 notificationService.sendOrderConfirmation(customerId, orderId); notificationService.sendPaymentConfirmation(customerId, transactionId); notificationService.sendShippingNotification(customerId, trackingNumber); System.out.println("购买流程完成!订单号: " + orderId + ", 跟踪号: " + trackingNumber + "\n"); return true; } // 简化的退货接口 public boolean returnProduct(String orderId, String customerId, double refundAmount) { System.out.println("=== 开始退货流程 ==="); System.out.println("订单号: " + orderId + ", 客户: " + customerId + ", 退款金额: $" + refundAmount); System.out.println("----------------------------------------"); // 1. 处理退款 paymentService.refund("REF" + System.currentTimeMillis(), refundAmount); // 2. 更新订单状态 orderService.updateOrderStatus(orderId, "已退货"); // 3. 发送通知 notificationService.sendPaymentConfirmation(customerId, "REF" + System.currentTimeMillis()); System.out.println("退货流程完成!\n"); return true; } } // 客户端代码 public class OnlineShoppingDemo { public static void main(String[] args) { System.out.println("=== 在线购物外观模式演示 ==="); // 创建购物外观 OnlineShoppingFacade shopping = new OnlineShoppingFacade(); // 购买商品 - 简单接口 boolean success1 = shopping.purchaseProduct("CUST001", "PROD123", 2, 99.99); if (success1) { System.out.println("第一次购买成功!\n"); } else { System.out.println("第一次购买失败!\n"); } // 再次购买商品 boolean success2 = shopping.purchaseProduct("CUST002", "PROD456", 1, 199.99); if (success2) { System.out.println("第二次购买成功!\n"); } else { System.out.println("第二次购买失败!\n"); } // 退货处理 if (success1) { shopping.returnProduct("ORD" + System.currentTimeMillis(), "CUST001", 199.98); } } } ``` ### 优缺点 #### 优点 1. **简化客户端使用**:为复杂的子系统提供简单的接口 2. **解耦客户端和子系统**:客户端不需要了解子系统的内部实现 3. **提高安全性**:可以隐藏子系统的内部实现细节 4. **更好的层次结构**:有助于建立层次化的系统结构 5. **符合迪米特法则**:减少了客户端与子系统的依赖关系 6. **易于维护**:子系统的修改不会影响客户端代码 #### 缺点 1. **可能成为上帝对象**:外观类可能变得过于庞大和复杂 2. **限制了灵活性**:客户端无法直接访问子系统的高级功能 3. **增加抽象层**:可能带来额外的性能开销 4. **违反开闭原则**:外观类可能需要频繁修改以适应子系统变化 ### 与其他模式的关系 1. **与抽象工厂模式**:外观模式可以使用抽象工厂来创建子系统对象 2. **与单例模式**:外观类通常实现为单例 3. **与适配器模式**:适配器模式改变接口,外观模式简化接口 4. **与装饰器模式**:装饰器模式扩展功能,外观模式简化使用 ### 实际应用场景 1. **API网关**:为微服务提供统一的访问入口 2. **数据库访问层**:封装复杂的数据库操作 3. **第三方库集成**:简化第三方库的使用 4. **系统配置**:封装复杂的系统配置过程 5. **UI组件库**:提供简化的组件使用接口 6. **网络通信**:封装复杂的网络协议交互 7. **文件处理**:封装复杂的文件读写操作 8. **业务流程**:封装复杂的业务处理流程 外观模式通过提供简化的接口来隐藏复杂子系统的实现细节,使得客户端可以更容易地使用这些系统,是软件设计中非常实用的模式之一。 ## 享元模式 享元模式(Flyweight Pattern)是结构型设计模式之一,主要用于减少创建对象的数量,以减少内存占用和提高性能。它通过共享技术有效地支持大量细粒度的对象。 ### 核心思想 享元模式的核心思想是**共享对象**,即通过复用已存在的对象来减少创建新对象的数量,从而降低系统内存消耗和提升性能。它特别适用于系统中存在大量相似对象的场景。 ### 核心概念 1. **Flyweight(享元对象)**:定义一个接口,通过它可以接受并作用于外部状态。 2. **ConcreteFlyweight(具体享元对象)**:实现Flyweight接口,为内部状态提供存储空间。 3. **UnsharedConcreteFlyweight(非共享具体享元对象)**:不需要共享的Flyweight子类。 4. **FlyweightFactory(享元工厂)**:负责创建和管理享元对象,确保享元对象可以被适当地共享。 5. **内部状态与外部状态**: - 内部状态:存储在享元对象内部,不会随环境改变而改变。 - 外部状态:随环境改变而改变,不能共享,需要客户端保存并在使用时传入。 ![06享元模式.png](img/03structural/06享元模式.png) ### 适用场景 - 系统中存在大量相似对象 - 需要缓冲池的场景 - 对象的大部分状态可以外部化 - 使用了大量细粒度对象,导致内存开销过大 ### 示例代码 ```java // 享元接口 interface Shape { void draw(int x, int y); } // 具体享元类 class Circle implements Shape { private String color; public Circle(String color) { this.color = color; System.out.println("Creating circle of color: " + color); } @Override public void draw(int x, int y) { System.out.println("Drawing circle of color: " + color + " at (" + x + ", " + y + ")"); } } // 享元工厂 class ShapeFactory { private static final Map circleMap = new HashMap<>(); public static Shape getCircle(String color) { Circle circle = (Circle) circleMap.get(color); if (circle == null) { circle = new Circle(color); circleMap.put(color, circle); System.out.println("Creating circle of color: " + color); } return circle; } } // 客户端代码 public class FlyweightPatternDemo { private static final String[] colors = {"Red", "Green", "Blue", "White", "Black"}; public static void main(String[] args) { for (int i = 0; i < 20; i++) { Circle circle = (Circle) ShapeFactory.getCircle(getRandomColor()); circle.draw(getRandomX(), getRandomY()); } } private static String getRandomColor() { return colors[(int) (Math.random() * colors.length)]; } private static int getRandomX() { return (int) (Math.random() * 100); } private static int getRandomY() { return (int) (Math.random() * 100); } } ``` ### 优缺点 #### 优点 1. **降低内存占用**:通过共享对象,显著减少对象数量,从而降低内存消耗 2. **提高性能**:减少创建和销毁对象的开销 3. **提升系统性能**:特别是在需要大量相似对象的场景下 #### 缺点 1. **增加系统复杂性**:需要区分内部状态和外部状态,使系统变得复杂 2. **外部状态可能影响性能**:读取外部状态需要时间,可能会影响性能 3. **线程安全问题**:在多线程环境下需要额外考虑线程安全问题 ### 总结 享元模式通过对象共享来减少内存使用,适用于需要大量相似对象的场景。在使用时需要仔细区分内部状态和外部状态,合理设计才能发挥其优势。该模式在Java的String常量池、数据库连接池等场景中都有广泛应用。 ## 代理模式 ### 核心思想 代理模式的核心思想是在客户端和目标对象之间设置一个代理对象,通过代理对象来间接访问目标对象。这样可以在不改变目标对象的前提下,增加额外的功能操作,如访问控制、延迟加载、日志记录等。 ### 核心概念 1. **Subject(抽象主题)**:声明了真实主题和代理主题的共同接口,使代理可以替代真实主题。 2. **RealSubject(真实主题)**:定义了代理所代表的真实对象,是实际执行业务逻辑的地方。 3. **Proxy(代理主题)**:持有对真实主题的引用,控制对真实主题的访问,并可能负责创建和删除真实主题。 4. **Client(客户端)**:通过代理接口访问真实主题。 ### 适用场景 - **远程代理**:为不同地址空间的对象提供本地代表 - **虚拟代理**:根据需要创建开销很大的对象 - **保护代理**:控制对原始对象的访问权限 - **智能引用**:在访问对象时执行额外操作(如引用计数) - **缓存代理**:为开销大的运算结果提供暂时存储 ### 示例代码 ```java // 抽象主题接口 interface Image { void display(); } // 真实主题类 class RealImage implements Image { private String fileName; public RealImage(String fileName) { this.fileName = fileName; loadFromDisk(); } private void loadFromDisk() { System.out.println("Loading " + fileName); } @Override public void display() { System.out.println("Displaying " + fileName); } } // 代理类 class ProxyImage implements Image { private RealImage realImage; private String fileName; public ProxyImage(String fileName) { this.fileName = fileName; } @Override public void display() { if (realImage == null) { realImage = new RealImage(fileName); } realImage.display(); } } // 客户端代码 public class ProxyPatternDemo { public static void main(String[] args) { Image image = new ProxyImage("test_10mb.jpg"); // 图像将从磁盘加载 image.display(); System.out.println(""); // 图像不需要从磁盘加载 image.display(); } } ``` ### 优缺点 ### 优点 1. **职责分离**:将客户端与真实主题分离,降低系统耦合度 2. **增强功能**:可以在访问真实主题前后添加额外功能 3. **延迟加载**:可以根据需要创建开销很大的对象 4. **访问控制**:可以控制客户端对真实主题的访问权限 5. **简化客户端**:客户端无需直接处理复杂对象的创建和管理 ### 缺点 1. **增加复杂性**:引入代理对象会增加系统的复杂度 2. **性能开销**:可能会增加请求的处理时间 3. **难以调试**:由于引入了间接层,可能使调试变得困难 ### 静态代理 #### 核心概念 静态代理是在编译时就已经确定了代理类和被代理类的关系。代理类和被代理类实现相同的接口,代理类持有被代理类的实例。 ![07代理模式静态代理.png](img/03structural/07代理模式静态代理.png) #### 示例代码 ```java // 抽象主题接口 interface UserService { void addUser(String username); String getUser(int id); } // 真实主题类 class UserServiceImpl implements UserService { @Override public void addUser(String username) { System.out.println("添加用户: " + username); } @Override public String getUser(int id) { System.out.println("查询用户ID: " + id); return "User" + id; } } // 静态代理类 class UserServiceProxy implements UserService { private UserService userService; public UserServiceProxy(UserService userService) { this.userService = userService; } @Override public void addUser(String username) { System.out.println("开启事务"); userService.addUser(username); System.out.println("提交事务"); } @Override public String getUser(int id) { System.out.println("开启事务"); String result = userService.getUser(id); System.out.println("提交事务"); return result; } } // 客户端代码 public class StaticProxyDemo { public static void main(String[] args) { UserService userService = new UserServiceImpl(); UserService proxy = new UserServiceProxy(userService); proxy.addUser("张三"); System.out.println(proxy.getUser(1)); } } ``` #### 优缺点 **优点:** - 实现简单,易于理解和维护 - 可以在不修改目标对象的前提下,增加额外功能 **缺点:** - 代理类和被代理类需要实现相同的接口,增加代码量 - 每个被代理类都需要一个对应的代理类,系统中类的数量增加 - 接口增加方法时,代理类和被代理类都需要修改 ### 动态代理(Dynamic Proxy) #### 核心概念 动态代理是在运行时动态生成代理类,不需要为每个被代理类编写具体的代理类。Java提供了两种动态代理实现方式:JDK动态代理和CGLIB动态代理。 #### JDK动态代理 JDK动态代理基于接口实现,要求被代理类必须实现接口。 ![07代理模式JDK动态代理.png](img/03structural/07代理模式JDK动态代理.png) ```java import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; // 抽象主题接口 interface OrderService { void createOrder(String orderInfo); String getOrder(int orderId); } // 真实主题类 class OrderServiceImpl implements OrderService { @Override public void createOrder(String orderInfo) { System.out.println("创建订单: " + orderInfo); } @Override public String getOrder(int orderId) { System.out.println("查询订单ID: " + orderId); return "Order" + orderId; } } // 动态代理处理器 class LoggingInvocationHandler implements InvocationHandler { private Object target; public LoggingInvocationHandler(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("开始执行方法: " + method.getName()); // 执行目标方法 Object result = method.invoke(target, args); System.out.println("方法执行完成: " + method.getName()); return result; } } // 客户端代码 public class JdkDynamicProxyDemo { public static void main(String[] args) { OrderService orderService = new OrderServiceImpl(); // 创建动态代理对象 OrderService proxy = (OrderService) Proxy.newProxyInstance( orderService.getClass().getClassLoader(), orderService.getClass().getInterfaces(), new LoggingInvocationHandler(orderService) ); proxy.createOrder("订单信息"); System.out.println(proxy.getOrder(123)); // 查看代理类信息 System.out.println("代理类名称: " + proxy.getClass().getName()); } } ``` #### CGLIB动态代理 CGLIB动态代理基于继承实现,可以代理没有实现接口的类。 ![07代理模式CGLB动态代理.png](img/03structural/07代理模式CGLB动态代理.png) ```java import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.Method; // 真实主题类(不需要实现接口) class ProductService { public void addProduct(String productName) { System.out.println("添加产品: " + productName); } public String getProduct(int productId) { System.out.println("查询产品ID: " + productId); return "Product" + productId; } } // CGLIB代理拦截器 class CglibMethodInterceptor implements MethodInterceptor { @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("CGLIB代理开始: " + method.getName()); // 执行目标方法 Object result = proxy.invokeSuper(obj, args); System.out.println("CGLIB代理结束: " + method.getName()); return result; } } // 客户端代码 public class CglibDynamicProxyDemo { public static void main(String[] args) { // 创建Enhancer对象 Enhancer enhancer = new Enhancer(); // 设置父类 enhancer.setSuperclass(ProductService.class); // 设置回调 enhancer.setCallback(new CglibMethodInterceptor()); // 创建代理对象 ProductService proxy = (ProductService) enhancer.create(); proxy.addProduct("手机"); System.out.println(proxy.getProduct(456)); // 查看代理类信息 System.out.println("代理类名称: " + proxy.getClass().getName()); } } ``` #### 动态代理优缺点 **优点:** - 减少代理类的数量,一个代理类可以代理多个不同的被代理对象 - 更加灵活,可以在运行时动态创建代理对象 - 降低了系统耦合度 **缺点:** - 实现相对复杂 - JDK动态代理只能代理实现了接口的类 - CGLIB动态代理需要引入第三方库 - 性能略低于静态代理(但通常可以接受) ### 静态代理与动态代理对比 | 特性 | 静态代理 | JDK动态代理 | CGLIB动态代理 | | -------------- | -------------- | ------------ | -------------- | | 实现方式 | 手动编写代理类 | 基于接口反射 | 基于字节码操作 | | 代理对象 | 编译时确定 | 运行时生成 | 运行时生成 | | 被代理对象要求 | 实现接口 | 必须实现接口 | 无需实现接口 | | 性能 | 较高 | 中等 | 中等 | | 灵活性 | 较低 | 高 | 高 | | 代码复杂度 | 简单 | 中等 | 中等 | 在实际应用中,Spring AOP就是综合运用了JDK动态代理和CGLIB动态代理,根据被代理对象是否实现接口来选择合适的代理方式。 # 七、行为型模式 ## 模板方法 ### 核心思想 模板方法模式的核心思想是**定义算法骨架,延迟具体实现**。在抽象类中定义一个或多个抽象方法,由子类实现这些抽象方法,从而在不改变算法结构的前提下,实现不同的行为。 ### 核心概念 1. **AbstractClass(抽象类)**:定义抽象的原语操作,具体的子类将重定义它们以实现一个算法的各步骤。主要是实现一个模板方法,定义一个算法的骨架。 2. **ConcreteClass(具体类)**:实现原语操作以完成算法中与特定子类相关的步骤。 3. **Template Method(模板方法)**:定义算法的骨架,按某种顺序调用其所有步骤方法。 4. **Hook Method(钩子方法)**:在抽象类中提供默认实现,子类可以选择性地覆盖它们。 ![01模板方法模式.png](img/04behavioral/01模板方法模式.png) ### 适用场景 - 算法的整体步骤很固定,但某些部分易变 - 多个子类有共同的行为,且逻辑基本相同 - 控制子类扩展,模板方法只在特定点调用"hook"操作 - 需要通过父类来控制子类的执行顺序 ### 示例代码 ```java // 抽象类 - 游戏 abstract class Game { // 模板方法,定义游戏流程 public final void play() { // 初始化游戏 initialize(); // 开始游戏 startPlay(); // 添加游戏特定的初始化 if (hasInitSpecific()) { initSpecific(); } // 游戏进行中 while (!endOfGame()) { makePlay(); } // 结束游戏 endPlay(); } // 基本方法 - 子类必须实现 abstract void initialize(); abstract void startPlay(); abstract void makePlay(); abstract boolean endOfGame(); abstract void endPlay(); // 钩子方法 - 子类可选择性实现 boolean hasInitSpecific() { return false; } // 钩子方法 - 子类可选择性覆盖 void initSpecific() { // 默认实现为空 } } // 具体类 - 象棋游戏 class Chess extends Game { @Override void initialize() { System.out.println("象棋游戏初始化"); } @Override void startPlay() { System.out.println("象棋游戏开始"); } @Override void makePlay() { System.out.println("走棋"); } @Override boolean endOfGame() { System.out.println("检查游戏是否结束"); return true; // 简化示例,直接返回true } @Override void endPlay() { System.out.println("象棋游戏结束"); } @Override boolean hasInitSpecific() { return true; } @Override void initSpecific() { System.out.println("象棋特定初始化"); } } // 具体类 - 足球游戏 class Football extends Game { @Override void initialize() { System.out.println("足球游戏初始化"); } @Override void startPlay() { System.out.println("足球游戏开始"); } @Override void makePlay() { System.out.println("踢球"); } @Override boolean endOfGame() { System.out.println("检查比赛是否结束"); return true; // 简化示例,直接返回true } @Override void endPlay() { System.out.println("足球游戏结束"); } } // 客户端代码 public class TemplatePatternDemo { public static void main(String[] args) { System.out.println("开始玩象棋:"); Game game = new Chess(); game.play(); System.out.println("\n开始踢足球:"); game = new Football(); game.play(); } } ``` ### 更复杂的示例 - 饮料制作模板 ```java // 抽象类 - 饮料制作 abstract class BeverageMaker { // 模板方法 - final防止子类覆盖 public final void prepareRecipe() { boilWater(); brew(); pourInCup(); // 条件钩子方法 if (customerWantsCondiments()) { addCondiments(); } } // 具体方法 - 所有子类共用 void boilWater() { System.out.println("煮沸水"); } // 抽象方法 - 子类必须实现 abstract void brew(); void pourInCup() { System.out.println("倒入杯中"); } // 抽象方法 - 子类必须实现 abstract void addCondiments(); // 钩子方法 - 子类可选择性覆盖 boolean customerWantsCondiments() { return true; } } // 具体类 - 制作咖啡 class Coffee extends BeverageMaker { @Override void brew() { System.out.println("用沸水冲泡咖啡粉"); } @Override void addCondiments() { System.out.println("加糖和牛奶"); } // 覆盖钩子方法 @Override boolean customerWantsCondiments() { System.out.println("您想要在咖啡中加糖和牛奶吗?(y/n)"); // 简化示例,直接返回true return true; } } // 具体类 - 制作茶 class Tea extends BeverageMaker { @Override void brew() { System.out.println("用沸水浸泡茶叶"); } @Override void addCondiments() { System.out.println("加柠檬"); } // 覆盖钩子方法 @Override boolean customerWantsCondiments() { System.out.println("您想要在茶中加柠檬吗?(y/n)"); // 简化示例,直接返回false return false; } } // 客户端代码 public class BeverageDemo { public static void main(String[] args) { System.out.println("制作咖啡:"); BeverageMaker coffee = new Coffee(); coffee.prepareRecipe(); System.out.println("\n制作茶:"); BeverageMaker tea = new Tea(); tea.prepareRecipe(); } } ``` ### 优缺点 #### 优点 1. **封装不变部分,扩展可变部分**:把认为是不变行为的算法封装到父类实现,而可变的部分算法行为则可以通过继承来扩展 2. **提取公共代码,便于维护**:将公共的行为抽取到一个公共父类中,避免代码重复 3. **行为由父类控制,子类实现**:通过父类调用其子类的操作(通过子类扩展功能),通过对子类的扩展增加新的行为,符合开闭原则 4. **便于控制子类扩展**:模板方法通过在特定点调用"hook"操作,只允许在这些点进行扩展 #### 缺点 1. **每个不同的实现都需要一个子类来实现**:导致类的个数增加,系统更加庞大 2. **违背里氏替换原则**:在添加新的抽象方法时,可能需要修改抽象类,影响所有子类 3. **模板方法执行流程固定**:算法骨架固定,不易于扩展 ### 模板方法模式在实际应用中的例子 1. **Servlet API**:`HttpServlet`类中的`service()`方法就是一个模板方法 2. **Spring框架**:`JdbcTemplate`、`HibernateTemplate`等 3. **Android开发**:Activity的生命周期方法 4. **JUnit测试框架**:测试执行的模板方法 模板方法模式是设计模式中较为简单但非常实用的一种模式,它通过定义算法骨架来规范子类的行为,同时允许子类在特定点进行个性化实现,是一种很好的代码复用和扩展机制。 ## 命令模式 命令模式(Command Pattern)是一种行为型设计模式,它将请求封装成对象,从而使你可以用不同的请求对客户进行参数化,对请求排队或记录请求日志,以及支持可撤销的操作。 ### 核心思想 命令模式的核心思想是**将请求封装成对象**,将发出请求的对象和执行请求的对象解耦。通过引入命令对象,可以实现请求的参数化、排队、记录日志、撤销等操作。 ### 核心概念 1. **Command(命令接口)**:声明执行操作的接口 2. **ConcreteCommand(具体命令类)**:将一个接收者对象与一个动作绑定,调用接收者相应的操作 3. **Client(客户端)**:创建具体命令对象并设定其接收者 4. **Invoker(调用者)**:要求该命令执行这个请求 5. **Receiver(接收者)**:知道如何实施与执行一个请求相关的操作 ![02命令模式.png](img/04behavioral/02命令模式.png) ### 适用场景 - 需要参数化对象以执行操作 - 需要将操作排队或记录操作日志 - 需要支持撤销操作 - 系统需要在不同时间指定、排列和执行请求 - 系统需要将请求发送者和接收者解耦 ### 示例代码 #### 基础命令模式实现 ```java // 命令接口 interface Command { void execute(); } // 接收者类 - 电灯 class Light { public void on() { System.out.println("电灯打开了"); } public void off() { System.out.println("电灯关闭了"); } } // 接收者类 - 风扇 class Fan { public void start() { System.out.println("风扇启动了"); } public void stop() { System.out.println("风扇停止了"); } } // 具体命令类 - 开灯命令 class LightOnCommand implements Command { private Light light; public LightOnCommand(Light light) { this.light = light; } @Override public void execute() { light.on(); } } // 具体命令类 - 关灯命令 class LightOffCommand implements Command { private Light light; public LightOffCommand(Light light) { this.light = light; } @Override public void execute() { light.off(); } } // 具体命令类 - 启动风扇命令 class FanStartCommand implements Command { private Fan fan; public FanStartCommand(Fan fan) { this.fan = fan; } @Override public void execute() { fan.start(); } } // 具体命令类 - 停止风扇命令 class FanStopCommand implements Command { private Fan fan; public FanStopCommand(Fan fan) { this.fan = fan; } @Override public void execute() { fan.stop(); } } // 调用者类 - 遥控器 class RemoteControl { private Command command; public void setCommand(Command command) { this.command = command; } public void pressButton() { command.execute(); } } // 客户端代码 public class CommandPatternDemo { public static void main(String[] args) { // 创建接收者 Light light = new Light(); Fan fan = new Fan(); // 创建命令对象 Command lightOn = new LightOnCommand(light); Command lightOff = new LightOffCommand(light); Command fanStart = new FanStartCommand(fan); Command fanStop = new FanStopCommand(fan); // 创建调用者 RemoteControl remote = new RemoteControl(); // 测试命令执行 remote.setCommand(lightOn); remote.pressButton(); remote.setCommand(fanStart); remote.pressButton(); remote.setCommand(lightOff); remote.pressButton(); remote.setCommand(fanStop); remote.pressButton(); } } ``` #### 支持撤销操作的命令模式 ```java // 支持撤销的命令接口 interface CommandWithUndo { void execute(); void undo(); } // 接收者类 - 计算器 class Calculator { private int currentValue = 0; public void add(int value) { System.out.println("执行加法: " + currentValue + " + " + value); currentValue += value; System.out.println("当前值: " + currentValue); } public void subtract(int value) { System.out.println("执行减法: " + currentValue + " - " + value); currentValue -= value; System.out.println("当前值: " + currentValue); } public int getCurrentValue() { return currentValue; } } // 具体命令类 - 加法命令 class AddCommand implements CommandWithUndo { private Calculator calculator; private int value; private int previousValue; public AddCommand(Calculator calculator, int value) { this.calculator = calculator; this.value = value; } @Override public void execute() { previousValue = calculator.getCurrentValue(); calculator.add(value); } @Override public void undo() { System.out.println("撤销加法操作: " + (previousValue + value) + " -> " + previousValue); // 简化实现,实际应该有更精确的撤销逻辑 } } // 具体命令类 - 减法命令 class SubtractCommand implements CommandWithUndo { private Calculator calculator; private int value; private int previousValue; public SubtractCommand(Calculator calculator, int value) { this.calculator = calculator; this.value = value; } @Override public void execute() { previousValue = calculator.getCurrentValue(); calculator.subtract(value); } @Override public void undo() { System.out.println("撤销减法操作: " + (previousValue - value) + " -> " + previousValue); // 简化实现,实际应该有更精确的撤销逻辑 } } // 调用者类 - 计算器控制器 class CalculatorController { private CommandWithUndo[] commands = new CommandWithUndo[10]; private int commandCount = 0; private int current = 0; public void executeCommand(CommandWithUndo command) { command.execute(); commands[current] = command; current++; commandCount = current; } public void undo() { if (current > 0) { current--; commands[current].undo(); } else { System.out.println("无法撤销,已到达操作开始位置"); } } public void redo() { if (current < commandCount) { commands[current].execute(); current++; } else { System.out.println("无法重做,已到达操作结束位置"); } } } // 客户端代码 public class UndoCommandDemo { public static void main(String[] args) { Calculator calculator = new Calculator(); CalculatorController controller = new CalculatorController(); // 执行一系列操作 controller.executeCommand(new AddCommand(calculator, 10)); controller.executeCommand(new SubtractCommand(calculator, 5)); controller.executeCommand(new AddCommand(calculator, 3)); System.out.println("当前计算器值: " + calculator.getCurrentValue()); System.out.println("--- 开始撤销操作 ---"); // 撤销操作 controller.undo(); // 撤销加3 controller.undo(); // 撤销减5 controller.undo(); // 撤销加10 System.out.println("--- 开始重做操作 ---"); // 重做操作 controller.redo(); // 重做加10 controller.redo(); // 重做减5 controller.redo(); // 重做加3 } } ``` #### 命令队列实现 ```java import java.util.*; // 命令队列管理器 class CommandQueue { private Queue commandQueue = new LinkedList<>(); public void addCommand(Command command) { commandQueue.offer(command); System.out.println("命令已添加到队列"); } public void processCommands() { System.out.println("开始处理命令队列..."); while (!commandQueue.isEmpty()) { Command command = commandQueue.poll(); command.execute(); } System.out.println("命令队列处理完成"); } } // 宏命令 - 执行多个命令 class MacroCommand implements Command { private List commands = new ArrayList<>(); public void addCommand(Command command) { commands.add(command); } public void removeCommand(Command command) { commands.remove(command); } @Override public void execute() { System.out.println("执行宏命令:"); for (Command command : commands) { command.execute(); } } } // 接收者 - 文本编辑器 class TextEditor { private StringBuilder content = new StringBuilder(); public void write(String text) { content.append(text); System.out.println("写入文本: " + text); System.out.println("当前内容: " + content.toString()); } public void delete(int count) { if (content.length() >= count) { String deleted = content.substring(content.length() - count); content.delete(content.length() - count, content.length()); System.out.println("删除文本: " + deleted); System.out.println("当前内容: " + content.toString()); } } public String getContent() { return content.toString(); } } // 具体命令 - 写入文本命令 class WriteTextCommand implements Command { private TextEditor editor; private String text; public WriteTextCommand(TextEditor editor, String text) { this.editor = editor; this.text = text; } @Override public void execute() { editor.write(text); } } // 具体命令 - 删除文本命令 class DeleteTextCommand implements Command { private TextEditor editor; private int count; public DeleteTextCommand(TextEditor editor, int count) { this.editor = editor; this.count = count; } @Override public void execute() { editor.delete(count); } } // 客户端代码 public class CommandQueueDemo { public static void main(String[] args) { TextEditor editor = new TextEditor(); CommandQueue queue = new CommandQueue(); // 创建命令 Command cmd1 = new WriteTextCommand(editor, "Hello "); Command cmd2 = new WriteTextCommand(editor, "World!"); Command cmd3 = new DeleteTextCommand(editor, 1); Command cmd4 = new WriteTextCommand(editor, " Command Pattern"); // 添加命令到队列 queue.addCommand(cmd1); queue.addCommand(cmd2); queue.addCommand(cmd3); queue.addCommand(cmd4); // 处理命令队列 queue.processCommands(); System.out.println("最终内容: " + editor.getContent()); // 演示宏命令 System.out.println("\n--- 演示宏命令 ---"); MacroCommand macro = new MacroCommand(); macro.addCommand(new WriteTextCommand(editor, "\n")); macro.addCommand(new WriteTextCommand(editor, "This is ")); macro.addCommand(new WriteTextCommand(editor, "a macro command")); macro.execute(); System.out.println("最终内容: " + editor.getContent()); } } ``` ### 优缺点 #### 优点 1. **降低系统耦合度**:将调用操作的对象与知道如何实现该操作的对象解耦 2. **扩展性好**:增加新的命令很容易,无需修改现有类 3. **支持撤销操作**:可以方便地实现命令的撤销和重做功能 4. **支持命令队列**:可以将命令对象存储在队列中,实现命令的排队执行 5. **支持日志记录**:可以将命令对象存储在日志中,用于系统故障恢复 6. **支持事务行为**:可以将多个命令组合成一个复合命令 #### 缺点 1. **增加系统复杂性**:可能会导致系统中存在过多的具体命令类 2. **内存开销**:每个命令都是一个对象,可能会占用较多内存 3. **开发工作量**:每增加一个具体命令类都需要编写对应的类 ### 命令模式的实际应用场景 1. **GUI菜单和工具栏**:每个菜单项或工具按钮都可以是一个命令对象 2. **多级撤销操作**:文本编辑器、绘图软件等需要支持撤销功能 3. **任务队列系统**:将任务封装为命令对象,放入队列中依次执行 4. **日志系统**:将操作记录为命令对象,用于系统恢复 5. **远程过程调用(RPC)**:将远程调用封装为命令对象 6. **游戏开发**:将玩家操作封装为命令对象,支持回放功能 7. **Spring中的JdbcTemplate** 命令模式是一个非常实用的设计模式,特别适用于需要将操作参数化、支持撤销、排队执行等场景。它是实现高内聚低耦合设计原则的典型例子。 ## 访问者模式 访问者模式(Visitor Pattern)是一种行为型设计模式,它允许你在不修改已有元素类层次结构的情况下,为这些元素定义新的操作。访问者模式将数据结构与数据操作分离,使得操作集合可以相对自由地演化。 ### 核心思想 访问者模式的核心思想是**将数据结构与作用于结构上的操作分离**。通过将操作封装在访问者对象中,可以为元素类层次结构添加新的操作,而无需修改现有的类。 ### 核心概念 1. **Visitor(访问者接口)**:为对象结构中的每个具体元素类声明一个访问方法 2. **ConcreteVisitor(具体访问者)**:实现每个由Visitor声明的操作,定义对元素的访问操作 3. **Element(元素接口)**:定义一个accept方法,以一个访问者为参数 4. **ConcreteElement(具体元素)**:实现accept操作,通常调用访问者的访问方法并将自身作为参数传入 5. **ObjectStructure(对象结构)**:能枚举它的元素,可以提供一个高层的接口以允许访问者访问它的元素 ![03访问者模式.png](img/04behavioral/03访问者模式.png) ### 适用场景 - 对一个对象结构中的对象进行很多不同的并且不相关的操作 - 需要对一个对象结构中的对象进行很多不同且不相关的操作,而不想污染这些类 - 对象结构中类很少改变,但经常需要在此结构上定义新的操作 - 双重分派的场景(需要根据访问者和元素的类型来决定执行的操作) ### 示例代码 #### 基础访问者模式实现 ```java // 访问者接口 interface Visitor { void visit(Book book); void visit(CD cd); void visit(DVD dvd); } // 元素接口 interface ItemElement { void accept(Visitor visitor); double getPrice(); String getName(); } // 具体元素 - 书籍 class Book implements ItemElement { private double price; private String name; private String isbnNumber; public Book(double price, String name, String isbn) { this.price = price; this.name = name; this.isbnNumber = isbn; } public double getPrice() { return price; } public String getName() { return name; } public String getIsbnNumber() { return isbnNumber; } @Override public void accept(Visitor visitor) { visitor.visit(this); } } // 具体元素 - CD class CD implements ItemElement { private double price; private String name; private String artist; public CD(double price, String name, String artist) { this.price = price; this.name = name; this.artist = artist; } public double getPrice() { return price; } public String getName() { return name; } public String getArtist() { return artist; } @Override public void accept(Visitor visitor) { visitor.visit(this); } } // 具体元素 - DVD class DVD implements ItemElement { private double price; private String name; private String director; public DVD(double price, String name, String director) { this.price = price; this.name = name; this.director = director; } public double getPrice() { return price; } public String getName() { return name; } public String getDirector() { return director; } @Override public void accept(Visitor visitor) { visitor.visit(this); } } // 具体访问者 - 价格计算访问者 class PriceVisitor implements Visitor { private double totalCost = 0; @Override public void visit(Book book) { System.out.println("书籍: " + book.getName() + ", 价格: $" + book.getPrice()); totalCost += book.getPrice(); } @Override public void visit(CD cd) { System.out.println("CD: " + cd.getName() + " by " + cd.getArtist() + ", 价格: $" + cd.getPrice()); totalCost += cd.getPrice(); } @Override public void visit(DVD dvd) { System.out.println("DVD: " + dvd.getName() + " directed by " + dvd.getDirector() + ", 价格: $" + dvd.getPrice()); totalCost += dvd.getPrice(); } public double getTotalCost() { return totalCost; } } // 具体访问者 - 详细信息访问者 class DetailsVisitor implements Visitor { @Override public void visit(Book book) { System.out.println("书籍详情 - 名称: " + book.getName() + ", ISBN: " + book.getIsbnNumber() + ", 价格: $" + book.getPrice()); } @Override public void visit(CD cd) { System.out.println("CD详情 - 名称: " + cd.getName() + ", 艺术家: " + cd.getArtist() + ", 价格: $" + cd.getPrice()); } @Override public void visit(DVD dvd) { System.out.println("DVD详情 - 名称: " + dvd.getName() + ", 导演: " + dvd.getDirector() + ", 价格: $" + dvd.getPrice()); } } // 对象结构 class ShoppingCart { private List items = new ArrayList<>(); public void addItem(ItemElement item) { items.add(item); } public void removeItem(ItemElement item) { items.remove(item); } public double calculateTotal() { PriceVisitor visitor = new PriceVisitor(); for (ItemElement item : items) { item.accept(visitor); } return visitor.getTotalCost(); } public void showDetails() { DetailsVisitor visitor = new DetailsVisitor(); for (ItemElement item : items) { item.accept(visitor); } } } // 客户端代码 public class VisitorPatternDemo { public static void main(String[] args) { ShoppingCart cart = new ShoppingCart(); // 添加商品 cart.addItem(new Book(20.0, "设计模式", "ISBN123")); cart.addItem(new CD(15.0, "流行音乐", "张三")); cart.addItem(new DVD(25.0, "科幻电影", "李四")); cart.addItem(new Book(30.0, "Java编程", "ISBN456")); System.out.println("=== 商品详情 ==="); cart.showDetails(); System.out.println("\n=== 总价计算 ==="); double total = cart.calculateTotal(); System.out.println("购物车总价: $" + total); } } ``` #### 复杂访问者模式示例 - 员工管理系统 ```java // 员工访问者接口 interface EmployeeVisitor { void visit(FullTimeEmployee employee); void visit(PartTimeEmployee employee); void visit(Manager manager); } // 员工元素接口 interface Employee { void accept(EmployeeVisitor visitor); String getName(); double getSalary(); } // 全职员工 class FullTimeEmployee implements Employee { private String name; private double salary; private int vacationDays; public FullTimeEmployee(String name, double salary, int vacationDays) { this.name = name; this.salary = salary; this.vacationDays = vacationDays; } public String getName() { return name; } public double getSalary() { return salary; } public int getVacationDays() { return vacationDays; } @Override public void accept(EmployeeVisitor visitor) { visitor.visit(this); } } // 兼职员工 class PartTimeEmployee implements Employee { private String name; private double hourlyRate; private int hoursWorked; public PartTimeEmployee(String name, double hourlyRate, int hoursWorked) { this.name = name; this.hourlyRate = hourlyRate; this.hoursWorked = hoursWorked; } public String getName() { return name; } public double getSalary() { return hourlyRate * hoursWorked; } public double getHourlyRate() { return hourlyRate; } public int getHoursWorked() { return hoursWorked; } @Override public void accept(EmployeeVisitor visitor) { visitor.visit(this); } } // 管理者 class Manager implements Employee { private String name; private double salary; private double bonus; public Manager(String name, double salary, double bonus) { this.name = name; this.salary = salary; this.bonus = bonus; } public String getName() { return name; } public double getSalary() { return salary + bonus; } public double getBaseSalary() { return salary; } public double getBonus() { return bonus; } @Override public void accept(EmployeeVisitor visitor) { visitor.visit(this); } } // 薪资计算访问者 class SalaryCalculatorVisitor implements EmployeeVisitor { private double totalSalary = 0; @Override public void visit(FullTimeEmployee employee) { totalSalary += employee.getSalary(); System.out.println("全职员工 " + employee.getName() + " 薪资: $" + employee.getSalary()); } @Override public void visit(PartTimeEmployee employee) { totalSalary += employee.getSalary(); System.out.println("兼职员工 " + employee.getName() + " 薪资: $" + employee.getSalary() + " (" + employee.getHoursWorked() + "小时 × $" + employee.getHourlyRate() + "/小时)"); } @Override public void visit(Manager manager) { totalSalary += manager.getSalary(); System.out.println("管理者 " + manager.getName() + " 薪资: $" + manager.getSalary() + " (基本薪资: $" + manager.getBaseSalary() + " + 奖金: $" + manager.getBonus() + ")"); } public double getTotalSalary() { return totalSalary; } } // 假期管理访问者 class VacationManagementVisitor implements EmployeeVisitor { private int totalVacationDays = 0; @Override public void visit(FullTimeEmployee employee) { totalVacationDays += employee.getVacationDays(); System.out.println("全职员工 " + employee.getName() + " 年假: " + employee.getVacationDays() + " 天"); } @Override public void visit(PartTimeEmployee employee) { System.out.println("兼职员工 " + employee.getName() + " 无年假"); } @Override public void visit(Manager manager) { int managerVacationDays = 25; // 管理者年假 totalVacationDays += managerVacationDays; System.out.println("管理者 " + manager.getName() + " 年假: " + managerVacationDays + " 天"); } public int getTotalVacationDays() { return totalVacationDays; } } // 员工报表访问者 class ReportVisitor implements EmployeeVisitor { private List reportLines = new ArrayList<>(); @Override public void visit(FullTimeEmployee employee) { reportLines.add("全职员工: " + employee.getName() + ", 薪资: $" + employee.getSalary() + ", 年假: " + employee.getVacationDays() + " 天"); } @Override public void visit(PartTimeEmployee employee) { reportLines.add("兼职员工: " + employee.getName() + ", 薪资: $" + employee.getSalary() + ", 工作时间: " + employee.getHoursWorked() + " 小时"); } @Override public void visit(Manager manager) { reportLines.add("管理者: " + manager.getName() + ", 薪资: $" + manager.getSalary() + ", 基本薪资: $" + manager.getBaseSalary() + ", 奖金: $" + manager.getBonus()); } public void printReport() { System.out.println("=== 员工报表 ==="); for (String line : reportLines) { System.out.println(line); } } } // 员工管理器 class EmployeeManager { private List employees = new ArrayList<>(); public void addEmployee(Employee employee) { employees.add(employee); } public void removeEmployee(Employee employee) { employees.remove(employee); } public double calculateTotalSalary() { SalaryCalculatorVisitor visitor = new SalaryCalculatorVisitor(); for (Employee employee : employees) { employee.accept(visitor); } return visitor.getTotalSalary(); } public int calculateTotalVacationDays() { VacationManagementVisitor visitor = new VacationManagementVisitor(); for (Employee employee : employees) { employee.accept(visitor); } return visitor.getTotalVacationDays(); } public void generateReport() { ReportVisitor visitor = new ReportVisitor(); for (Employee employee : employees) { employee.accept(visitor); } visitor.printReport(); } } // 客户端代码 public class EmployeeVisitorDemo { public static void main(String[] args) { EmployeeManager manager = new EmployeeManager(); // 添加员工 manager.addEmployee(new FullTimeEmployee("张三", 5000, 15)); manager.addEmployee(new FullTimeEmployee("李四", 6000, 18)); manager.addEmployee(new PartTimeEmployee("王五", 30, 80)); manager.addEmployee(new Manager("赵六", 8000, 2000)); manager.addEmployee(new PartTimeEmployee("钱七", 25, 120)); System.out.println("=== 薪资计算 ==="); double totalSalary = manager.calculateTotalSalary(); System.out.println("总薪资支出: $" + totalSalary); System.out.println("\n=== 假期管理 ==="); int totalVacationDays = manager.calculateTotalVacationDays(); System.out.println("总年假天数: " + totalVacationDays + " 天"); System.out.println(); manager.generateReport(); } } ``` ### 优缺点 #### 优点 1. **扩展性好**:可以在不修改元素类的情况下添加新的操作 2. **集中相关操作**:相关操作可以集中在一个访问者中,便于维护 3. **分离无关行为**:将不相关的操作从元素类中分离出来 4. **灵活性高**:可以在运行时选择不同的访问者来执行不同的操作 5. **符合开闭原则**:对扩展开放,对修改关闭 #### 缺点 1. **违反封装性**:访问者需要了解元素的内部细节 2. **增加系统复杂性**:需要为每种元素类型定义访问方法 3. **难以维护**:当元素类层次结构变化时,需要修改所有访问者 4. **双重分派复杂性**:理解和实现双重分派机制较为复杂 ### 访问者模式的实际应用场景 1. **编译器设计**:抽象语法树的遍历和操作 2. **XML文档处理**:对XML节点进行不同类型的处理 3. **GUI组件处理**:对不同类型的GUI组件执行操作 4. **报表生成**:对不同类型的数据对象生成报表 5. **财务系统**:对不同类型的财务对象进行计算和分析 6. **游戏开发**:对游戏中的不同对象执行操作 访问者模式是一个相对复杂的模式,适用于需要在不修改现有类的情况下为对象结构添加新操作的场景。它通过双重分派机制实现了操作与对象结构的分离,但需要权衡封装性和扩展性。 ## 迭代器模式 迭代器模式(Iterator Pattern)是一种行为型设计模式,它提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露该对象的内部表示。迭代器模式将数据的遍历操作从聚合对象中分离出来,使得聚合对象可以专注于数据的存储和管理。 ### 核心思想 迭代器模式的核心思想是**将数据的遍历操作与数据的存储结构分离**,通过引入迭代器对象来统一不同数据结构的遍历接口,使得客户端可以以统一的方式遍历不同的聚合对象。 ### 核心概念 1. **Iterator(迭代器接口)**:定义访问和遍历元素的接口 2. **ConcreteIterator(具体迭代器)**:实现迭代器接口,跟踪遍历聚合时的当前位置 3. **Aggregate(聚合接口)**:定义创建相应迭代器对象的接口 4. **ConcreteAggregate(具体聚合)**:实现创建相应迭代器的接口,返回ConcreteIterator实例 ![04迭代器模式.png](img/04behavioral/04迭代器模式.png) ### 适用场景 - 需要访问一个聚合对象的内容而无需暴露其内部表示 - 需要支持对聚合对象的多种遍历方式 - 需要为遍历不同的聚合结构提供一个统一的接口 - 聚合对象的数据结构可能经常变化,但遍历方式相对稳定 ### 示例代码 #### 基础迭代器模式实现 ```java // 迭代器接口 interface Iterator { boolean hasNext(); T next(); void remove(); } // 聚合接口 interface Aggregate { Iterator createIterator(); } // 具体聚合 - 书籍集合 class BookCollection implements Aggregate { private List books = new ArrayList<>(); public void addBook(Book book) { books.add(book); } public void removeBook(Book book) { books.remove(book); } public int size() { return books.size(); } public Book get(int index) { if (index >= 0 && index < books.size()) { return books.get(index); } return null; } @Override public Iterator createIterator() { return new BookIterator(this); } } // 具体迭代器 class BookIterator implements Iterator { private BookCollection collection; private int position = 0; public BookIterator(BookCollection collection) { this.collection = collection; } @Override public boolean hasNext() { return position < collection.size(); } @Override public Book next() { if (hasNext()) { return collection.get(position++); } return null; } @Override public void remove() { if (position > 0) { collection.removeBook(collection.get(--position)); } } } // 书籍实体类 class Book { private String title; private String author; private String isbn; public Book(String title, String author, String isbn) { this.title = title; this.author = author; this.isbn = isbn; } public String getTitle() { return title; } public String getAuthor() { return author; } public String getIsbn() { return isbn; } @Override public String toString() { return "Book{title='" + title + "', author='" + author + "', isbn='" + isbn + "'}"; } } // 客户端代码 public class IteratorPatternDemo { public static void main(String[] args) { // 创建书籍集合 BookCollection collection = new BookCollection(); collection.addBook(new Book("设计模式", "Gang of Four", "ISBN001")); collection.addBook(new Book("Java编程思想", "Bruce Eckel", "ISBN002")); collection.addBook(new Book("重构", "Martin Fowler", "ISBN003")); collection.addBook(new Book("代码大全", "Steve McConnell", "ISBN004")); // 使用迭代器遍历 System.out.println("=== 使用迭代器遍历书籍 ==="); Iterator iterator = collection.createIterator(); while (iterator.hasNext()) { Book book = iterator.next(); System.out.println(book); } // 重新获取迭代器并删除某些元素 System.out.println("\n=== 删除特定书籍后遍历 ==="); iterator = collection.createIterator(); while (iterator.hasNext()) { Book book = iterator.next(); if ("重构".equals(book.getTitle())) { iterator.remove(); System.out.println("已删除书籍: " + book.getTitle()); } } // 再次遍历 System.out.println("\n=== 删除后的书籍列表 ==="); iterator = collection.createIterator(); while (iterator.hasNext()) { Book book = iterator.next(); System.out.println(book); } } } ``` #### 复杂迭代器模式示例 - 多种遍历方式 ```java // 增强版迭代器接口 interface AdvancedIterator { boolean hasNext(); T next(); boolean hasPrevious(); T previous(); void first(); void last(); int currentIndex(); } // 双向迭代器实现 class BidirectionalIterator implements AdvancedIterator { private List list; private int currentIndex; public BidirectionalIterator(List list) { this.list = list; this.currentIndex = 0; } @Override public boolean hasNext() { return currentIndex < list.size(); } @Override public T next() { if (hasNext()) { return list.get(currentIndex++); } return null; } @Override public boolean hasPrevious() { return currentIndex > 0; } @Override public T previous() { if (hasPrevious()) { return list.get(--currentIndex); } return null; } @Override public void first() { currentIndex = 0; } @Override public void last() { currentIndex = list.size(); } @Override public int currentIndex() { return currentIndex; } } // 过滤迭代器 class FilterIterator implements Iterator { private Iterator iterator; private Predicate predicate; private T nextItem; private boolean hasNextItem; public FilterIterator(Iterator iterator, Predicate predicate) { this.iterator = iterator; this.predicate = predicate; findNext(); } private void findNext() { hasNextItem = false; while (iterator.hasNext()) { nextItem = iterator.next(); if (predicate.test(nextItem)) { hasNextItem = true; break; } } } @Override public boolean hasNext() { return hasNextItem; } @Override public T next() { if (!hasNextItem) { throw new NoSuchElementException(); } T result = nextItem; findNext(); return result; } @Override public void remove() { iterator.remove(); } } // 跳过迭代器 class SkipIterator implements Iterator { private Iterator iterator; private int skipCount; private int currentSkip; public SkipIterator(Iterator iterator, int skipCount) { this.iterator = iterator; this.skipCount = skipCount; this.currentSkip = 0; } @Override public boolean hasNext() { return iterator.hasNext(); } @Override public T next() { while (iterator.hasNext()) { T item = iterator.next(); if (currentSkip == 0) { currentSkip = skipCount; return item; } currentSkip--; } throw new NoSuchElementException(); } @Override public void remove() { iterator.remove(); } } // 员工实体类 class Employee { private String name; private String department; private double salary; private int age; public Employee(String name, String department, double salary, int age) { this.name = name; this.department = department; this.salary = salary; this.age = age; } public String getName() { return name; } public String getDepartment() { return department; } public double getSalary() { return salary; } public int getAge() { return age; } @Override public String toString() { return "Employee{name='" + name + "', department='" + department + "', salary=" + salary + ", age=" + age + "}"; } } // 员工集合 class EmployeeCollection implements Aggregate { private List employees = new ArrayList<>(); public void addEmployee(Employee employee) { employees.add(employee); } public void removeEmployee(Employee employee) { employees.remove(employee); } public Employee get(int index) { if (index >= 0 && index < employees.size()) { return employees.get(index); } return null; } public int size() { return employees.size(); } public List getEmployees() { return new ArrayList<>(employees); // 返回副本以保护内部结构 } @Override public Iterator createIterator() { return new EmployeeIterator(this); } // 创建双向迭代器 public AdvancedIterator createBidirectionalIterator() { return new BidirectionalIterator<>(employees); } // 创建过滤迭代器 public Iterator createFilterIterator(Predicate predicate) { return new FilterIterator<>(createIterator(), predicate); } // 创建跳过迭代器 public Iterator createSkipIterator(int skipCount) { return new SkipIterator<>(createIterator(), skipCount); } } // 员工迭代器 class EmployeeIterator implements Iterator { private EmployeeCollection collection; private int position = 0; public EmployeeIterator(EmployeeCollection collection) { this.collection = collection; } @Override public boolean hasNext() { return position < collection.size(); } @Override public Employee next() { if (hasNext()) { return collection.get(position++); } throw new NoSuchElementException(); } @Override public void remove() { if (position > 0) { collection.removeEmployee(collection.get(--position)); } } } // 客户端代码 public class AdvancedIteratorDemo { public static void main(String[] args) { // 创建员工集合 EmployeeCollection employees = new EmployeeCollection(); employees.addEmployee(new Employee("张三", "技术部", 8000, 28)); employees.addEmployee(new Employee("李四", "销售部", 6000, 32)); employees.addEmployee(new Employee("王五", "技术部", 9000, 25)); employees.addEmployee(new Employee("赵六", "人事部", 7000, 30)); employees.addEmployee(new Employee("钱七", "技术部", 12000, 35)); employees.addEmployee(new Employee("孙八", "销售部", 6500, 27)); System.out.println("=== 基本迭代器遍历 ==="); Iterator basicIterator = employees.createIterator(); while (basicIterator.hasNext()) { System.out.println(basicIterator.next()); } System.out.println("\n=== 双向迭代器遍历 ==="); AdvancedIterator biIterator = employees.createBidirectionalIterator(); System.out.println("正向遍历:"); while (biIterator.hasNext()) { System.out.println(biIterator.next()); } System.out.println("\n反向遍历:"); biIterator.last(); while (biIterator.hasPrevious()) { System.out.println(biIterator.previous()); } System.out.println("\n=== 过滤迭代器遍历(只显示技术部员工)==="); Iterator filterIterator = employees.createFilterIterator( emp -> "技术部".equals(emp.getDepartment()) ); while (filterIterator.hasNext()) { System.out.println(filterIterator.next()); } System.out.println("\n=== 过滤迭代器遍历(只显示高薪员工)==="); Iterator highSalaryIterator = employees.createFilterIterator( emp -> emp.getSalary() > 8000 ); while (highSalaryIterator.hasNext()) { System.out.println(highSalaryIterator.next()); } System.out.println("\n=== 跳过迭代器遍历(每隔一个员工显示一个)==="); Iterator skipIterator = employees.createSkipIterator(1); while (skipIterator.hasNext()) { System.out.println(skipIterator.next()); } } } ``` #### 自定义集合类的迭代器实现 ```java // 树形结构节点 class TreeNode { private T data; private List> children; private TreeNode parent; public TreeNode(T data) { this.data = data; this.children = new ArrayList<>(); } public void addChild(TreeNode child) { child.parent = this; children.add(child); } public T getData() { return data; } public List> getChildren() { return children; } public TreeNode getParent() { return parent; } public boolean isLeaf() { return children.isEmpty(); } @Override public String toString() { return data.toString(); } } // 树的深度优先迭代器 class TreeDepthFirstIterator implements Iterator { private Stack> stack; public TreeDepthFirstIterator(TreeNode root) { stack = new Stack<>(); if (root != null) { stack.push(root); } } @Override public boolean hasNext() { return !stack.isEmpty(); } @Override public T next() { if (!hasNext()) { throw new NoSuchElementException(); } TreeNode node = stack.pop(); // 将子节点压入栈中(逆序压入以保证正确的遍历顺序) List> children = node.getChildren(); for (int i = children.size() - 1; i >= 0; i--) { stack.push(children.get(i)); } return node.getData(); } } // 树的广度优先迭代器 class TreeBreadthFirstIterator implements Iterator { private Queue> queue; public TreeBreadthFirstIterator(TreeNode root) { queue = new LinkedList<>(); if (root != null) { queue.offer(root); } } @Override public boolean hasNext() { return !queue.isEmpty(); } @Override public T next() { if (!hasNext()) { throw new NoSuchElementException(); } TreeNode node = queue.poll(); // 将子节点加入队列 for (TreeNode child : node.getChildren()) { queue.offer(child); } return node.getData(); } } // 树形结构聚合 class TreeAggregate implements Aggregate { private TreeNode root; public TreeAggregate(TreeNode root) { this.root = root; } @Override public Iterator createIterator() { return new TreeDepthFirstIterator<>(root); } public Iterator createDepthFirstIterator() { return new TreeDepthFirstIterator<>(root); } public Iterator createBreadthFirstIterator() { return new TreeBreadthFirstIterator<>(root); } } // 客户端代码 public class TreeIteratorDemo { public static void main(String[] args) { // 构建树形结构 TreeNode root = new TreeNode<>("根节点"); TreeNode node1 = new TreeNode<>("节点1"); TreeNode node2 = new TreeNode<>("节点2"); TreeNode node3 = new TreeNode<>("节点3"); root.addChild(node1); root.addChild(node2); root.addChild(node3); TreeNode node11 = new TreeNode<>("节点1-1"); TreeNode node12 = new TreeNode<>("节点1-2"); node1.addChild(node11); node1.addChild(node12); TreeNode node21 = new TreeNode<>("节点2-1"); node2.addChild(node21); TreeNode node111 = new TreeNode<>("节点1-1-1"); node11.addChild(node111); TreeAggregate tree = new TreeAggregate<>(root); System.out.println("=== 深度优先遍历 ==="); Iterator depthIterator = tree.createDepthFirstIterator(); while (depthIterator.hasNext()) { System.out.println(depthIterator.next()); } System.out.println("\n=== 广度优先遍历 ==="); Iterator breadthIterator = tree.createBreadthFirstIterator(); while (breadthIterator.hasNext()) { System.out.println(breadthIterator.next()); } } } ``` ### 优缺点 #### 优点 1. **简化聚合类**:聚合类不需要知道如何遍历自己的元素 2. **支持多种遍历方式**:可以为同一个聚合对象提供多种遍历方式 3. **统一接口**:为不同的聚合结构提供统一的遍历接口 4. **扩展性好**:可以轻松添加新的迭代器实现 5. **封装性好**:隐藏了聚合对象的内部表示 #### 缺点 1. **增加复杂性**:对于简单的聚合类,引入迭代器会增加系统复杂性 2. **内存开销**:每个迭代器都需要额外的内存来保存遍历状态 3. **性能开销**:某些复杂的迭代器实现可能会有性能开销 ### 迭代器模式的实际应用场景 1. **集合框架**:Java的Collection框架大量使用迭代器模式 2. **数据库查询结果**:ResultSet的遍历 3. **文件系统**:目录和文件的遍历 4. **XML/JSON解析**:节点的遍历 5. **图形界面**:组件树的遍历 6. **编译器**:抽象语法树的遍历 7. **游戏开发**:游戏对象的遍历 迭代器模式是一个非常实用的设计模式,它将数据的遍历操作与数据的存储结构分离,使得客户端可以以统一的方式遍历不同的聚合对象,同时保护了聚合对象的内部结构。 ## 观察者模式 观察者模式(Observer Pattern)是一种行为型设计模式,它定义了对象之间的一对多依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知并自动更新。观察者模式也被称为发布-订阅模式或模型-视图模式。 ### 核心思想 观察者模式的核心思想是**建立对象间的松耦合关系**,通过定义一种一对多的依赖关系,使得当一个对象的状态发生改变时,所有依赖于它的对象都能得到自动通知和更新。 ### 核心概念 1. **Subject(主题/被观察者)**:维护观察者列表,提供添加、删除和通知观察者的方法 2. **Observer(观察者)**:定义一个更新接口,供主题在状态改变时通知观察者 3. **ConcreteSubject(具体主题)**:实现主题接口,存储观察者感兴趣的状态,状态改变时通知观察者 4. **ConcreteObserver(具体观察者)**:实现观察者接口,维护指向具体主题的引用,实现更新接口 ![05观察者模式.png](img/04behavioral/05观察者模式.png) ### 适用场景 - 当一个对象的改变需要同时改变其他对象,而不知道具体有多少对象有待改变时 - 当一个抽象模型有两个方面,其中一个方面依赖于另一个方面时 - 当一个对象必须通知其他对象,而不能假定其他对象是谁时 - 需要在系统中创建一个触发链时 ### 示例代码 #### 基础观察者模式实现 ```java // 观察者接口 interface Observer { void update(String message); } // 主题接口 interface Subject { void addObserver(Observer observer); void removeObserver(Observer observer); void notifyObservers(String message); } // 具体主题 - 新闻发布者 class NewsPublisher implements Subject { private List observers; private String news; public NewsPublisher() { observers = new ArrayList<>(); } @Override public void addObserver(Observer observer) { if (!observers.contains(observer)) { observers.add(observer); } } @Override public void removeObserver(Observer observer) { observers.remove(observer); } @Override public void notifyObservers(String message) { for (Observer observer : observers) { observer.update(message); } } // 发布新闻 public void publishNews(String news) { this.news = news; System.out.println("新闻发布: " + news); notifyObservers(news); } public String getNews() { return news; } } // 具体观察者 - 新闻订阅者 class NewsSubscriber implements Observer { private String name; private String latestNews; public NewsSubscriber(String name) { this.name = name; } @Override public void update(String message) { this.latestNews = message; System.out.println(name + " 收到新闻更新: " + message); } public String getName() { return name; } public String getLatestNews() { return latestNews; } } // 客户端代码 public class BasicObserverDemo { public static void main(String[] args) { // 创建新闻发布者 NewsPublisher publisher = new NewsPublisher(); // 创建新闻订阅者 NewsSubscriber subscriber1 = new NewsSubscriber("张三"); NewsSubscriber subscriber2 = new NewsSubscriber("李四"); NewsSubscriber subscriber3 = new NewsSubscriber("王五"); // 订阅新闻 publisher.addObserver(subscriber1); publisher.addObserver(subscriber2); publisher.addObserver(subscriber3); // 发布新闻 System.out.println("=== 发布第一条新闻 ==="); publisher.publishNews("今天天气很好!"); System.out.println("\n=== 李四取消订阅 ==="); publisher.removeObserver(subscriber2); System.out.println("\n=== 发布第二条新闻 ==="); publisher.publishNews("明天有重要会议!"); System.out.println("\n=== 当前各订阅者收到的最新新闻 ==="); System.out.println(subscriber1.getName() + ": " + subscriber1.getLatestNews()); System.out.println(subscriber2.getName() + ": " + subscriber2.getLatestNews()); System.out.println(subscriber3.getName() + ": " + subscriber3.getLatestNews()); } } ``` #### 复杂观察者模式示例 - 股票交易系统 ```java // 股票信息类 class Stock { private String symbol; private double price; private double change; private Date lastUpdate; public Stock(String symbol, double price) { this.symbol = symbol; this.price = price; this.lastUpdate = new Date(); } public void setPrice(double price) { this.change = price - this.price; this.price = price; this.lastUpdate = new Date(); } // Getter 方法 public String getSymbol() { return symbol; } public double getPrice() { return price; } public double getChange() { return change; } public Date getLastUpdate() { return lastUpdate; } @Override public String toString() { return String.format("Stock{symbol='%s', price=%.2f, change=%.2f}", symbol, price, change); } } // 股票观察者接口 interface StockObserver { void update(Stock stock); } // 股票主题接口 interface StockSubject { void addObserver(StockObserver observer); void removeObserver(StockObserver observer); void notifyObservers(); } // 具体股票主题 class StockMarket implements StockSubject { private List observers; private Map stocks; public StockMarket() { observers = new ArrayList<>(); stocks = new HashMap<>(); } @Override public void addObserver(StockObserver observer) { if (!observers.contains(observer)) { observers.add(observer); } } @Override public void removeObserver(StockObserver observer) { observers.remove(observer); } @Override public void notifyObservers() { for (StockObserver observer : observers) { for (Stock stock : stocks.values()) { observer.update(stock); } } } // 添加股票 public void addStock(Stock stock) { stocks.put(stock.getSymbol(), stock); } // 更新股票价格 public void updateStockPrice(String symbol, double newPrice) { Stock stock = stocks.get(symbol); if (stock != null) { stock.setPrice(newPrice); System.out.println("股票 " + symbol + " 价格更新为: " + newPrice); notifyObservers(); } } public Stock getStock(String symbol) { return stocks.get(symbol); } } // 具体观察者 - 价格显示器 class PriceDisplay implements StockObserver { private String name; public PriceDisplay(String name) { this.name = name; } @Override public void update(Stock stock) { System.out.println(name + " 显示: " + stock); } } // 具体观察者 - 交易员 class Trader implements StockObserver { private String name; private Map portfolio; public Trader(String name) { this.name = name; this.portfolio = new HashMap<>(); } @Override public void update(Stock stock) { String symbol = stock.getSymbol(); double price = stock.getPrice(); double change = stock.getChange(); System.out.println(name + " 收到股票 " + symbol + " 更新: 当前价格 " + price + ", 变化 " + (change >= 0 ? "+" : "") + change); // 根据价格变化做出交易决策 if (change > 0 && portfolio.containsKey(symbol)) { System.out.println(name + " 考虑卖出 " + symbol + " 股票"); } else if (change < 0) { System.out.println(name + " 考虑买入 " + symbol + " 股票"); } } public void buyStock(String symbol, double price) { portfolio.put(symbol, price); System.out.println(name + " 买入 " + symbol + " 股票,价格: " + price); } public void sellStock(String symbol) { if (portfolio.containsKey(symbol)) { System.out.println(name + " 卖出 " + symbol + " 股票"); portfolio.remove(symbol); } } } // 具体观察者 - 警报系统 class AlertSystem implements StockObserver { private double threshold; public AlertSystem(double threshold) { this.threshold = threshold; } @Override public void update(Stock stock) { double change = Math.abs(stock.getChange()); if (change >= threshold) { System.out.println("*** 警报 *** " + stock.getSymbol() + " 价格波动超过阈值 " + threshold + ",当前波动: " + change); } } } // 客户端代码 public class StockMarketDemo { public static void main(String[] args) throws InterruptedException { // 创建股票市场 StockMarket market = new StockMarket(); // 添加股票 market.addStock(new Stock("AAPL", 150.0)); market.addStock(new Stock("GOOGL", 2800.0)); market.addStock(new Stock("TSLA", 800.0)); // 创建观察者 PriceDisplay display1 = new PriceDisplay("主显示屏"); PriceDisplay display2 = new PriceDisplay("副显示屏"); Trader trader1 = new Trader("张交易员"); Trader trader2 = new Trader("李交易员"); AlertSystem alertSystem = new AlertSystem(10.0); // 注册观察者 market.addObserver(display1); market.addObserver(display2); market.addObserver(trader1); market.addObserver(trader2); market.addObserver(alertSystem); // 交易员买入股票 trader1.buyStock("AAPL", 145.0); trader2.buyStock("TSLA", 750.0); System.out.println("\n=== 开始股票价格更新 ==="); // 模拟股票价格变化 market.updateStockPrice("AAPL", 155.0); // +5.0 Thread.sleep(1000); market.updateStockPrice("GOOGL", 2850.0); // +50.0 Thread.sleep(1000); market.updateStockPrice("TSLA", 900.0); // +100.0 (触发警报) Thread.sleep(1000); market.updateStockPrice("AAPL", 140.0); // -15.0 (触发警报) Thread.sleep(1000); System.out.println("\n=== 移除副显示屏观察者 ==="); market.removeObserver(display2); market.updateStockPrice("GOOGL", 2900.0); // +50.0 } } ``` #### 推模型和拉模型的观察者模式 ```java // 推模型 - 主题主动推送数据给观察者 interface PushObserver { void update(String symbol, double price, double change); } // 拉模型 - 观察者主动从主题拉取数据 interface PullObserver { void update(StockMarketPull market); } // 拉模型的主题 class StockMarketPull { private List observers; private Map stocks; public StockMarketPull() { observers = new ArrayList<>(); stocks = new HashMap<>(); } public void addObserver(PullObserver observer) { if (!observers.contains(observer)) { observers.add(observer); } } public void removeObserver(PullObserver observer) { observers.remove(observer); } public void notifyObservers() { for (PullObserver observer : observers) { observer.update(this); // 推送主题引用,让观察者自己拉取数据 } } public void addStock(Stock stock) { stocks.put(stock.getSymbol(), stock); } public void updateStockPrice(String symbol, double newPrice) { Stock stock = stocks.get(symbol); if (stock != null) { stock.setPrice(newPrice); System.out.println("拉模型 - 股票 " + symbol + " 价格更新为: " + newPrice); notifyObservers(); } } // 提供给观察者拉取数据的方法 public Stock getStock(String symbol) { return stocks.get(symbol); } public Collection getAllStocks() { return stocks.values(); } } // 推模型观察者 class PushStockDisplay implements PushObserver { private String name; public PushStockDisplay(String name) { this.name = name; } @Override public void update(String symbol, double price, double change) { System.out.println(name + " (推模型) 接收到更新 - " + symbol + ": " + price + " (" + (change >= 0 ? "+" : "") + change + ")"); } } // 拉模型观察者 class PullStockDisplay implements PullObserver { private String name; public PullStockDisplay(String name) { this.name = name; } @Override public void update(StockMarketPull market) { System.out.println(name + " (拉模型) 开始拉取数据:"); for (Stock stock : market.getAllStocks()) { System.out.println(" " + name + " 获取到 - " + stock); } } } // 客户端代码 public class PushPullDemo { public static void main(String[] args) { System.out.println("=== 推模型示例 ==="); // 推模型示例 class PushStockSubject implements Subject { private List observers; private Map stocks; public PushStockSubject() { observers = new ArrayList<>(); stocks = new HashMap<>(); } @Override public void addObserver(Observer observer) { if (!observers.contains(observer)) { observers.add(observer); } } @Override public void removeObserver(Observer observer) { observers.remove(observer); } @Override public void notifyObservers(String message) { // 这里简化处理,实际应该传递具体的股票数据 for (Observer observer : observers) { observer.update(message); } } public void addStock(Stock stock) { stocks.put(stock.getSymbol(), stock); } public void updateStockPrice(String symbol, double newPrice) { Stock stock = stocks.get(symbol); if (stock != null) { double oldPrice = stock.getPrice(); stock.setPrice(newPrice); double change = newPrice - oldPrice; // 推送具体数据给观察者 for (Observer observer : observers) { if (observer instanceof PushStockDisplay) { ((PushStockDisplay) observer).update(symbol, newPrice, change); } } } } } PushStockSubject pushSubject = new PushStockSubject(); PushStockDisplay pushDisplay = new PushStockDisplay("推模型显示器"); pushSubject.addStock(new Stock("MSFT", 300.0)); // 注意:这里简化了Observer接口的使用 System.out.println("\n=== 拉模型示例 ==="); // 拉模型示例 StockMarketPull pullMarket = new StockMarketPull(); PullStockDisplay pullDisplay = new PullStockDisplay("拉模型显示器"); pullMarket.addObserver(pullDisplay); pullMarket.addStock(new Stock("MSFT", 300.0)); pullMarket.updateStockPrice("MSFT", 310.0); } } ``` ### 优缺点 #### 优点 1. **松耦合**:主题和观察者之间松耦合,可以独立变化 2. **支持广播通信**:主题可以通知所有观察者,而不需要指定具体的观察者 3. **符合开闭原则**:可以轻松添加新的观察者而不修改现有代码 4. **动态关系**:可以在运行时建立和删除观察者关系 5. **简化对象间的依赖关系**:避免了对象间的直接调用 #### 缺点 1. **内存泄漏风险**:如果忘记删除观察者,可能导致内存泄漏 2. **性能问题**:通知所有观察者可能影响性能,特别是观察者很多时 3. **意外的更新**:观察者不知道主题的变化原因,可能导致不必要的更新 4. **调试困难**:由于依赖关系复杂,调试可能比较困难 ### 观察者模式的实际应用场景 1. **GUI事件处理**:按钮点击、鼠标移动等事件处理 2. **MVC架构**:模型变化时通知视图更新 3. **消息订阅系统**:发布订阅模式的实现 4. **股票交易系统**:股价变化通知 5. **社交媒体**:用户动态更新通知 6. **游戏开发**:游戏状态变化通知 7. **IoC容器**:Spring框架中的事件机制 8. **响应式编程**:RxJava、React等框架的基础 观察者模式是一个非常重要的设计模式,它通过建立对象间的松耦合关系,实现了良好的可扩展性和可维护性。在现代软件开发中,观察者模式被广泛应用于各种场景中。 ## 中介者模式 ### 核心思想 中介者模式是一种行为型设计模式,其核心思想是**将多对多的对象交互关系转换为一对多的关系**,通过引入一个中介者对象来集中处理对象间的复杂交互,从而降低系统中对象之间的耦合度。 ### 核心概念 1. **Mediator(中介者接口)** - 定义了同事对象间通信的接口 - 各个同事对象通过该接口与中介者通信 2. **ConcreteMediator(具体中介者)** - 实现中介者接口 - 协调各个同事对象的交互关系 - 依赖于具体的同事对象 3. **Colleague(同事类)** - 每个同事类都知道中介者对象 - 每个同事对象在需要与其他同事通信时,通过中介者进行 4. **ConcreteColleague(具体同事类)** - 实现自己的业务逻辑 - 在需要与其它同事通信时,通过中介者转发消息 ![06中介者模式.png](img/04behavioral/06中介者模式.png) ### 适用场景 - **系统中对象之间存在复杂的引用关系**,导致结构混乱且难以理解 - **一组对象需要通信,但希望保持松耦合** - **想通过一个中间类来封装多个类的行为** - **多个类相互耦合,形成了网状结构** ### 示例代码 ```java // 中介者接口 abstract class Mediator { public abstract void sendMessage(String message, Colleague colleague); } // 具体中介者 class ChatMediator extends Mediator { private List colleagues; public ChatMediator() { colleagues = new ArrayList<>(); } public void addColleague(Colleague colleague) { colleagues.add(colleague); } @Override public void sendMessage(String message, Colleague sender) { for (Colleague colleague : colleagues) { // 不要发送给自己 if (colleague != sender) { colleague.receiveMessage(message); } } } } // 同事抽象类 abstract class Colleague { protected Mediator mediator; protected String name; public Colleague(Mediator mediator, String name) { this.mediator = mediator; this.name = name; } public abstract void sendMessage(String message); public abstract void receiveMessage(String message); } // 具体同事类 class User extends Colleague { public User(Mediator mediator, String name) { super(mediator, name); } @Override public void sendMessage(String message) { System.out.println(name + " 发送消息: " + message); mediator.sendMessage(message, this); } @Override public void receiveMessage(String message) { System.out.println(name + " 收到消息: " + message); } } // 使用示例 public class MediatorExample { public static void main(String[] args) { ChatMediator chatMediator = new ChatMediator(); User user1 = new User(chatMediator, "张三"); User user2 = new User(chatMediator, "李四"); User user3 = new User(chatMediator, "王五"); chatMediator.addColleague(user1); chatMediator.addColleague(user2); chatMediator.addColleague(user3); user1.sendMessage("大家好!"); System.out.println("------------------"); user2.sendMessage("你好,张三!"); } } ``` ### 优缺点 #### 优点 1. **降低耦合度** - 各个同事类之间解耦,它们不再需要直接引用彼此 - 只需要与中介者交互 2. **简化对象之间的交互** - 将一对多的交互复杂性变为一 对一的交互 - 使得系统更容易理解和维护 3. **提高可维护性** - 各个同事类的行为独立,使得可以独立地改变和复用各个类 - 中介者集中管理交互,便于统一修改 4. **符合迪米特法则** - 减少了对象之间的直接交互,降低了类之间的依赖关系 #### 缺点 1. **中介者类可能变得过于复杂** - 中介者需要知道所有同事类,可能导致中介者类膨胀 - 随着同事类的增加,中介者的逻辑会变得复杂 2. **中介者类可能成为系统的瓶颈** - 如果中介者承担过多职责,可能会影响系统性能 - 需要仔细设计中介者的职责范围 3. **增加系统复杂度** - 引入中介者类会增加系统的类数量 - 可能导致过度设计 ### 实际应用场景 - **聊天室系统**:用户通过聊天室进行消息转发 - **GUI组件交互**:多个界面组件通过控制器进行协调 - **机场调度系统**:飞机通过塔台进行通信和调度 - **MVC框架**:Controller作为中介者协调Model和View - **工作流系统**:各种任务通过工作流引擎进行协调 中介者模式通过将复杂的交互集中到中介者中,有效地降低了系统组件之间的耦合度,使得系统更易于维护和扩展。 ## 备忘录模式 ### 核心思想 备忘录模式是一种行为型设计模式,其核心思想是在不破坏封装性的前提下,**捕获一个对象的内部状态,并在该对象之外保存这个状态**,以便日后可以将该对象恢复到原先保存的状态。 ### 核心概念 1. **Originator(发起人)** - 需要保存内部状态的对象 - 创建备忘录对象来保存自身状态 - 从备忘录对象中恢复自身状态 2. **Memento(备忘录)** - 负责存储 `Originator` 对象的内部状态 - 防止 `Originator` 以外的其他对象访问备忘录 3. **Caretaker(管理者)** - 负责保存备忘录对象 - 不能对备忘录的内容进行操作或检查 - 只能将备忘录传递给其他对象 ![07备忘录模式.png](img/04behavioral/07备忘录模式.png) ### 适用场景 - **需要保存对象在某一时刻的状态**,并在适当的时候将其恢复 - **需要提供撤销操作的功能**(Undo操作) - **需要回滚操作**,例如数据库事务回滚 - **对象状态的外部化存储**,避免暴露对象的实现细节 - **需要创建对象状态快照**以供后续使用 ### 示例代码 ```java // 备忘录类 - 存储发起人的内部状态 class Memento { private String state; public Memento(String state) { this.state = state; } public String getState() { return state; } } // 发起人类 - 需要保存状态的对象 class Originator { private String state; public void setState(String state) { this.state = state; } public String getState() { return state; } // 创建备忘录 public Memento createMemento() { return new Memento(state); } // 从备忘录恢复状态 public void restoreMemento(Memento memento) { this.state = memento.getState(); } @Override public String toString() { return "当前状态: " + state; } } // 管理者类 - 负责保管备忘录 class Caretaker { private Memento memento; public void setMemento(Memento memento) { this.memento = memento; } public Memento getMemento() { return memento; } } // 使用示例 public class MementoExample { public static void main(String[] args) { // 创建发起人 Originator originator = new Originator(); // 创建管理者 Caretaker caretaker = new Caretaker(); // 设置初始状态 originator.setState("状态1"); System.out.println(originator); // 保存状态 caretaker.setMemento(originator.createMemento()); System.out.println("已保存状态"); // 修改状态 originator.setState("状态2"); System.out.println(originator); // 恢复状态 originator.restoreMemento(caretaker.getMemento()); System.out.println("恢复后: " + originator); } } ``` ### 更完整的示例 - 文本编辑器撤销功能 ```java // 文本编辑器状态备忘录 class TextMemento { private String content; private int cursorPosition; public TextMemento(String content, int cursorPosition) { this.content = content; this.cursorPosition = cursorPosition; } public String getContent() { return content; } public int getCursorPosition() { return cursorPosition; } } // 文本编辑器 - 发起人 class TextEditor { private String content; private int cursorPosition; public TextEditor() { this.content = ""; this.cursorPosition = 0; } public void type(String text) { this.content += text; this.cursorPosition = this.content.length(); } public void delete(int count) { if (count <= content.length()) { this.content = content.substring(0, content.length() - count); this.cursorPosition = this.content.length(); } } public TextMemento save() { return new TextMemento(content, cursorPosition); } public void restore(TextMemento memento) { this.content = memento.getContent(); this.cursorPosition = memento.getCursorPosition(); } @Override public String toString() { return "内容: '" + content + "', 光标位置: " + cursorPosition; } } // 历史记录管理器 - 管理者 class History { private Stack history = new Stack<>(); public void push(TextMemento memento) { history.push(memento); } public TextMemento pop() { return history.pop(); } public boolean isEmpty() { return history.isEmpty(); } } // 使用示例 public class TextEditorExample { public static void main(String[] args) { TextEditor editor = new TextEditor(); History history = new History(); // 输入文本 editor.type("Hello "); System.out.println(editor); // 保存状态 history.push(editor.save()); editor.type("World!"); System.out.println(editor); // 再次保存状态 history.push(editor.save()); editor.type(" How are you?"); System.out.println(editor); // 撤销操作 if (!history.isEmpty()) { editor.restore(history.pop()); System.out.println("撤销一次后: " + editor); } // 再次撤销 if (!history.isEmpty()) { editor.restore(history.pop()); System.out.println("再次撤销后: " + editor); } } } ``` ### 优缺点 #### 优点 1. **保护封装性** - 备忘录模式可以在不破坏封装的前提下实现状态的保存和恢复 - 对象无需暴露其内部结构即可保存和恢复状态 2. **简化发起人类** - 发起人不需要管理和保存其历史状态 - 状态的管理工作交给管理者完成 3. **提供撤销/恢复功能** - 可以方便地实现撤销操作 - 支持多次撤销和恢复 4. **灵活性强** - 可以根据需要决定保存哪些状态 - 可以设置不同的保存策略 #### 缺点 1. **消耗资源** - 如果需要保存的状态较多,会占用大量内存 - 频繁创建备忘录对象会产生额外开销 2. **可能违反开闭原则** - 当发起人的内部状态发生改变时,可能需要修改备忘录类 3. **管理复杂** - 需要管理备忘录的生命周期 - 需要考虑何时创建、何时删除备忘录 4. **潜在的安全风险** - 备忘录可能暴露对象的内部信息 - 需要合理控制对备忘录的访问权限 ### 实际应用场景 - **文本编辑器的撤销功能**:保存文档的历史状态 - **游戏存档系统**:保存游戏进度和状态 - **数据库事务管理**:实现事务回滚功能 - **浏览器的后退功能**:保存页面浏览历史 - **IDE的重构操作**:支持撤销重构操作 - **绘图软件**:保存画布的不同版本状态 备忘录模式通过在对象外部保存其内部状态,实现了对象状态的保存和恢复机制,在很多需要撤销操作或者状态回滚的场景中都有广泛应用。 ## 解释器模式 ### 核心思想 解释器模式是一种行为型设计模式,其核心思想是**定义一个语言的文法,并建立一个解释器来解释该语言中的句子**。它主要用于处理那些可以被分解为一系列简单规则的问题,这些规则可以用一种简单的语言来表示。 ### 核心概念 1. **AbstractExpression(抽象表达式)** - 声明一个抽象的解释操作接口 - 所有具体表达式类都实现这个接口 2. **TerminalExpression(终结符表达式)** - 实现文法中的终结符相关的解释操作 - 每个终结符都需要一个具体表达式类 3. **NonterminalExpression(非终结符表达式)** - 实现文法中的非终结符相关的解释操作 - 每个非终结符都需要一个具体表达式类 4. **Context(环境类)** - 包含解释器之外的一些全局信息 - 用来存储解释器需要的数据或公共功能 5. **Client(客户类)** - 构建表示文法规则的抽象语法树 - 调用解释操作 ![08解释器模式.png](img/04behavioral/08解释器模式.png) ### 适用场景 - **当有一个语言需要解释执行,并且可以将该语言中的句子表示为一个抽象语法树时** - **当文法比较简单时**(复杂的文法会导致类的数量急剧增加) - **当需要频繁地解释执行一些特定语言的句子时** - **当问题重复出现且可以用一种简单的语言来表达时** ### 示例代码 - 简单数学表达式计算器 ```java import java.util.*; // 上下文类 class Context { private Map variables; public Context() { variables = new HashMap<>(); } public void setVariable(String variable, Integer value) { variables.put(variable, value); } public Integer getVariable(String variable) { return variables.get(variable); } } // 抽象表达式 interface Expression { int interpret(Context context); } // 终结符表达式 - 数字 class NumberExpression implements Expression { private int number; public NumberExpression(int number) { this.number = number; } @Override public int interpret(Context context) { return number; } } // 终结符表达式 - 变量 class VariableExpression implements Expression { private String name; public VariableExpression(String name) { this.name = name; } @Override public int interpret(Context context) { return context.getVariable(name); } } // 非终结符表达式 - 加法 class AddExpression implements Expression { private Expression left; private Expression right; public AddExpression(Expression left, Expression right) { this.left = left; this.right = right; } @Override public int interpret(Context context) { return left.interpret(context) + right.interpret(context); } } // 非终结符表达式 - 减法 class SubtractExpression implements Expression { private Expression left; private Expression right; public SubtractExpression(Expression left, Expression right) { this.left = left; this.right = right; } @Override public int interpret(Context context) { return left.interpret(context) - right.interpret(context); } } // 非终结符表达式 - 乘法 class MultiplyExpression implements Expression { private Expression left; private Expression right; public MultiplyExpression(Expression left, Expression right) { this.left = left; this.right = right; } @Override public int interpret(Context context) { return left.interpret(context) * right.interpret(context); } } // 解析器工具类 class ExpressionParser { public static Expression parse(String expression) { // 这里简化处理,实际应用中需要更复杂的解析逻辑 String[] tokens = expression.split(" "); Stack stack = new Stack<>(); for (String token : tokens) { switch (token) { case "+": Expression rightAdd = stack.pop(); Expression leftAdd = stack.pop(); stack.push(new AddExpression(leftAdd, rightAdd)); break; case "-": Expression rightSub = stack.pop(); Expression leftSub = stack.pop(); stack.push(new SubtractExpression(leftSub, rightSub)); break; case "*": Expression rightMul = stack.pop(); Expression leftMul = stack.pop(); stack.push(new MultiplyExpression(leftMul, rightMul)); break; default: // 判断是否为数字 if (isNumber(token)) { stack.push(new NumberExpression(Integer.parseInt(token))); } else { // 变量 stack.push(new VariableExpression(token)); } break; } } return stack.pop(); } private static boolean isNumber(String str) { try { Integer.parseInt(str); return true; } catch (NumberFormatException e) { return false; } } } // 使用示例 public class InterpreterExample { public static void main(String[] args) { // 创建上下文并设置变量值 Context context = new Context(); context.setVariable("x", 10); context.setVariable("y", 5); context.setVariable("z", 2); // 解析并计算表达式: x y + z * // 相当于 (x + y) * z = (10 + 5) * 2 = 30 String expressionStr = "x y + z *"; Expression expression = ExpressionParser.parse(expressionStr); int result = expression.interpret(context); System.out.println("表达式 '" + expressionStr + "' 的结果是: " + result); // 解析并计算表达式: x z * y - // 相当于 x * z - y = 10 * 2 - 5 = 15 String expressionStr2 = "x z * y -"; Expression expression2 = ExpressionParser.parse(expressionStr2); int result2 = expression2.interpret(context); System.out.println("表达式 '" + expressionStr2 + "' 的结果是: " + result2); } } ``` ### 更完整的示例 - 布尔表达式解释器 ```java // 上下文类 class BooleanContext { private Map variables; public BooleanContext() { variables = new HashMap<>(); } public void setVariable(String variable, Boolean value) { variables.put(variable, value); } public Boolean getVariable(String variable) { return variables.get(variable); } } // 抽象表达式 interface BooleanExpression { boolean interpret(BooleanContext context); } // 终结符表达式 - 布尔常量 class ConstantExpression implements BooleanExpression { private boolean value; public ConstantExpression(boolean value) { this.value = value; } @Override public boolean interpret(BooleanContext context) { return value; } } // 终结符表达式 - 变量 class VariableBooleanExpression implements BooleanExpression { private String name; public VariableBooleanExpression(String name) { this.name = name; } @Override public boolean interpret(BooleanContext context) { return context.getVariable(name); } } // 非终结符表达式 - 与运算 class AndExpression implements BooleanExpression { private BooleanExpression left; private BooleanExpression right; public AndExpression(BooleanExpression left, BooleanExpression right) { this.left = left; this.right = right; } @Override public boolean interpret(BooleanContext context) { return left.interpret(context) && right.interpret(context); } } // 非终结符表达式 - 或运算 class OrExpression implements BooleanExpression { private BooleanExpression left; private BooleanExpression right; public OrExpression(BooleanExpression left, BooleanExpression right) { this.left = left; this.right = right; } @Override public boolean interpret(BooleanContext context) { return left.interpret(context) || right.interpret(context); } } // 非终结符表达式 - 非运算 class NotExpression implements BooleanExpression { private BooleanExpression expression; public NotExpression(BooleanExpression expression) { this.expression = expression; } @Override public boolean interpret(BooleanContext context) { return !expression.interpret(context); } } // 使用示例 public class BooleanInterpreterExample { public static void main(String[] args) { // 创建上下文并设置变量值 BooleanContext context = new BooleanContext(); context.setVariable("a", true); context.setVariable("b", false); context.setVariable("c", true); // 构造布尔表达式: (a AND b) OR (NOT c) BooleanExpression expression = new OrExpression( new AndExpression( new VariableBooleanExpression("a"), new VariableBooleanExpression("b") ), new NotExpression( new VariableBooleanExpression("c") ) ); boolean result = expression.interpret(context); System.out.println("表达式 (a AND b) OR (NOT c) 的结果是: " + result); // 构造布尔表达式: a AND (b OR c) BooleanExpression expression2 = new AndExpression( new VariableBooleanExpression("a"), new OrExpression( new VariableBooleanExpression("b"), new VariableBooleanExpression("c") ) ); boolean result2 = expression2.interpret(context); System.out.println("表达式 a AND (b OR c) 的结果是: " + result2); } } ``` ### 优点 1. **易于改变和扩展文法** - 可以通过继承等方式很容易地改变或扩展文法 - 每一条文法规则都可以表示为一个类,因此可以方便地实现文法 2. **易于实现文法** - 定义抽象语法树中各个节点的类的实现容易 - 类的层次结构反映了文法规则的层次结构 3. **增加了新的解释表达式的方式** - 可以在解释的同时增加一些新的行为,如打印输出、执行某些指令等 4. **灵活性强** - 可以动态构建抽象语法树 - 可以在运行时改变行为 ### 缺点 1. **对于复杂的文法难以维护** - 文法规则数目太多时,类的数目会急剧增长 - 系统难于管理和维护 2. **执行效率较低** - 在解释器模式中使用了大量的循环和递归调用 - 导致执行效率较低 3. **对于高度复杂的语法,基于类的设计较难实现** - 大多数时候采用语法分析器生成器会更好 4. **增加了系统复杂性** - 大量的类使得系统复杂度增加 - 需要深入理解文法规则 ### 实际应用场景 - **正则表达式解释器**:编译和执行正则表达式 - **SQL解析器**:解析SQL语句并执行 - **编程语言解释器**:小型脚本语言的解释执行 - **配置文件解析**:解析特定格式的配置文件 - **数学表达式计算器**:计算数学表达式的值 - **模板引擎**:解析和渲染模板语言 - **规则引擎**:执行业务规则 解释器模式通过将语言的文法规则表示为类,使得我们可以用面向对象的方式来处理语言解释问题。虽然对于复杂文法可能会产生大量的类,但在处理相对简单的语言或特定领域语言(DSL)时非常有用。 ## 状态模式 状态模式是一种行为型设计模式,其核心思想是**允许一个对象在其内部状态改变时改变它的行为**。对象看起来似乎修改了它的类。状态模式将不同状态的行为分割开来,把各种状态的转换逻辑分布到各个状态类中,从而简化了复杂的条件判断语句。 ### 核心思想 1. **State(抽象状态类)** - 定义一个接口以封装与Context的一个特定状态相关的行为 - 为所有具体状态类定义公共接口 2. **ConcreteState(具体状态类)** - 每一个子类实现一个与Context的一个状态相关的行为 - 处理来自Context的请求 3. **Context(环境类)** - 定义客户感兴趣的接口 - 维护一个ConcreteState子类的实例,这个实例定义当前状态 ![09状态模式.png](img/04behavioral/09状态模式.png) ### 适用场景 - **对象的行为依赖于它的状态,并且它必须在运行时刻根据状态改变它的行为** - **代码中包含大量与对象状态有关的条件语句**,这些条件语句的出现,会导致代码的可维护性和灵活性变差 - **需要根据对象的不同状态执行不同的操作** - **有明确的状态转换逻辑且状态较多时** ### 示例代码 - 订单状态管理系统 ```java // 抽象状态类 abstract class OrderState { protected OrderContext context; public void setContext(OrderContext context) { this.context = context; } // 抽象方法,由具体状态类实现 public abstract void createOrder(); // 创建订单 public abstract void payOrder(); // 支付订单 public abstract void shipOrder(); // 发货订单 public abstract void deliverOrder(); // 交付订单 public abstract void cancelOrder(); // 取消订单 public abstract String getStateName(); // 获取状态名称 } // 具体状态类 - 待创建状态 class CreatedState extends OrderState { @Override public void createOrder() { System.out.println("订单已创建"); context.setState(new PendingPaymentState()); } @Override public void payOrder() { System.out.println("请先创建订单"); } @Override public void shipOrder() { System.out.println("请先创建订单和支付"); } @Override public void deliverOrder() { System.out.println("请先创建订单、支付和发货"); } @Override public void cancelOrder() { System.out.println("订单已取消"); context.setState(new CancelledState()); } @Override public String getStateName() { return "待创建"; } } // 具体状态类 - 待支付状态 class PendingPaymentState extends OrderState { @Override public void createOrder() { System.out.println("订单已经创建,请进行支付"); } @Override public void payOrder() { System.out.println("订单已支付"); context.setState(new ShippedState()); } @Override public void shipOrder() { System.out.println("请先支付订单"); } @Override public void deliverOrder() { System.out.println("请先支付订单和发货"); } @Override public void cancelOrder() { System.out.println("订单已取消"); context.setState(new CancelledState()); } @Override public String getStateName() { return "待支付"; } } // 具体状态类 - 已发货状态 class ShippedState extends OrderState { @Override public void createOrder() { System.out.println("订单已经创建"); } @Override public void payOrder() { System.out.println("订单已经支付"); } @Override public void shipOrder() { System.out.println("订单已经发货"); } @Override public void deliverOrder() { System.out.println("订单已交付"); context.setState(new DeliveredState()); } @Override public void cancelOrder() { System.out.println("订单已取消"); context.setState(new CancelledState()); } @Override public String getStateName() { return "已发货"; } } // 具体状态类 - 已交付状态 class DeliveredState extends OrderState { @Override public void createOrder() { System.out.println("订单已完成"); } @Override public void payOrder() { System.out.println("订单已完成"); } @Override public void shipOrder() { System.out.println("订单已完成"); } @Override public void deliverOrder() { System.out.println("订单已完成"); } @Override public void cancelOrder() { System.out.println("订单已完成,无法取消"); } @Override public String getStateName() { return "已交付"; } } // 具体状态类 - 已取消状态 class CancelledState extends OrderState { @Override public void createOrder() { System.out.println("订单已取消,无法重新创建"); } @Override public void payOrder() { System.out.println("订单已取消,无法支付"); } @Override public void shipOrder() { System.out.println("订单已取消,无法发货"); } @Override public void deliverOrder() { System.out.println("订单已取消,无法交付"); } @Override public void cancelOrder() { System.out.println("订单已取消"); } @Override public String getStateName() { return "已取消"; } } // 环境类 - 订单上下文 class OrderContext { private OrderState state; public OrderContext() { // 初始状态为待创建状态 this.state = new CreatedState(); this.state.setContext(this); } public void setState(OrderState state) { this.state = state; this.state.setContext(this); System.out.println("订单状态已变更为: " + state.getStateName()); } public OrderState getState() { return state; } // 委托给当前状态处理 public void createOrder() { state.createOrder(); } public void payOrder() { state.payOrder(); } public void shipOrder() { state.shipOrder(); } public void deliverOrder() { state.deliverOrder(); } public void cancelOrder() { state.cancelOrder(); } public String getCurrentState() { return state.getStateName(); } } // 使用示例 public class OrderStateExample { public static void main(String[] args) { OrderContext order = new OrderContext(); System.out.println("=== 订单状态演示 ==="); System.out.println("当前状态: " + order.getCurrentState()); // 正常流程 order.createOrder(); System.out.println("当前状态: " + order.getCurrentState()); order.payOrder(); System.out.println("当前状态: " + order.getCurrentState()); order.shipOrder(); System.out.println("当前状态: " + order.getCurrentState()); order.deliverOrder(); System.out.println("当前状态: " + order.getCurrentState()); System.out.println("\n=== 尝试在已完成状态下操作 ==="); order.createOrder(); order.payOrder(); order.shipOrder(); order.deliverOrder(); order.cancelOrder(); } } ``` ### 更完整的示例 - 电梯控制系统 ```java // 抽象状态类 abstract class ElevatorState { protected ElevatorContext context; public void setContext(ElevatorContext context) { this.context = context; } // 电梯操作 public abstract void openDoor(); // 开门 public abstract void closeDoor(); // 关门 public abstract void goUp(); // 上升 public abstract void goDown(); // 下降 public abstract void stop(); // 停止 public abstract String getStateName(); // 获取状态名称 } // 具体状态类 - 开门状态 class OpenState extends ElevatorState { @Override public void openDoor() { System.out.println("门已经是开启状态"); } @Override public void closeDoor() { System.out.println("门已关闭"); context.setState(new CloseState()); } @Override public void goUp() { System.out.println("门开启时无法运行"); } @Override public void goDown() { System.out.println("门开启时无法运行"); } @Override public void stop() { System.out.println("电梯已停止"); } @Override public String getStateName() { return "开门状态"; } } // 具体状态类 - 关门状态 class CloseState extends ElevatorState { @Override public void openDoor() { System.out.println("门已开启"); context.setState(new OpenState()); } @Override public void closeDoor() { System.out.println("门已经是关闭状态"); } @Override public void goUp() { System.out.println("电梯开始上升"); context.setState(new RunState()); } @Override public void goDown() { System.out.println("电梯开始下降"); context.setState(new RunState()); } @Override public void stop() { System.out.println("电梯已停止"); } @Override public String getStateName() { return "关门状态"; } } // 具体状态类 - 运行状态 class RunState extends ElevatorState { @Override public void openDoor() { System.out.println("运行时无法开门"); } @Override public void closeDoor() { System.out.println("门已经是关闭状态"); } @Override public void goUp() { System.out.println("电梯正在上升"); } @Override public void goDown() { System.out.println("电梯正在下降"); } @Override public void stop() { System.out.println("电梯已停止"); context.setState(new StopState()); } @Override public String getStateName() { return "运行状态"; } } // 具体状态类 - 停止状态 class StopState extends ElevatorState { @Override public void openDoor() { System.out.println("门已开启"); context.setState(new OpenState()); } @Override public void closeDoor() { System.out.println("门已经是关闭状态"); } @Override public void goUp() { System.out.println("电梯开始上升"); context.setState(new RunState()); } @Override public void goDown() { System.out.println("电梯开始下降"); context.setState(new RunState()); } @Override public void stop() { System.out.println("电梯已停止"); } @Override public String getStateName() { return "停止状态"; } } // 环境类 - 电梯上下文 class ElevatorContext { private ElevatorState state; public ElevatorContext() { // 初始状态为停止状态 this.state = new StopState(); this.state.setContext(this); } public void setState(ElevatorState state) { this.state = state; this.state.setContext(this); System.out.println("电梯状态变更为: " + state.getStateName()); } public ElevatorState getState() { return state; } // 委托给当前状态处理 public void openDoor() { state.openDoor(); } public void closeDoor() { state.closeDoor(); } public void goUp() { state.goUp(); } public void goDown() { state.goDown(); } public void stop() { state.stop(); } public String getCurrentState() { return state.getStateName(); } } // 电梯演示 public class ElevatorExample { public static void main(String[] args) { ElevatorContext elevator = new ElevatorContext(); System.out.println("=== 电梯控制系统演示 ==="); System.out.println("当前状态: " + elevator.getCurrentState()); // 演示正常操作流程 elevator.openDoor(); elevator.closeDoor(); elevator.goUp(); elevator.stop(); elevator.openDoor(); System.out.println("\n=== 尝试非法操作 ==="); elevator.goDown(); // 在开门状态下尝试下降 elevator.closeDoor(); elevator.goDown(); elevator.openDoor(); // 在运行状态下尝试开门 } } ``` ### 优点 1. **封装了状态转换规则** - 将状态转换逻辑分布到各个状态类中,避免了庞大的条件分支语句 - 状态转换更加清晰明了 2. **符合开闭原则** - 增加新的状态类很容易,只需要实现抽象状态类 - 不需要修改已有的状态类和环境类 3. **简化了状态机的实现** - 每个状态都是一个独立的类,职责单一 - 代码结构清晰,易于理解和维护 4. **提高了代码的可维护性** - 状态相关的代码集中在相应的状态类中 - 修改某个状态的行为不会影响其他状态 5. **提高了代码的可扩展性** - 可以方便地增加新的状态和转换 - 支持状态的继承和多态 ### 缺点 1. **增加了系统中类的个数** - 状态类的数量会随着状态的增加而增加 - 可能导致系统中类的数量急剧增长 2. **状态之间的转换逻辑分散** - 状态转换逻辑分布在各个状态类中 - 不容易看出整个状态机的转换流程 3. **对象会驻留在内存中** - 每个状态都是一个对象,会占用一定的内存空间 - 对于简单的状态转换可能显得过于复杂 4. **增加了系统的复杂度** - 需要设计合理的状态继承体系 - 需要处理好状态之间的依赖关系 ### 实际应用场景 - **工作流系统**:处理不同阶段的业务流程 - **游戏开发**:游戏角色的不同状态(待机、攻击、防御等) - **网络连接管理**:TCP连接的不同状态(连接、监听、关闭等) - **播放器控制**:播放、暂停、停止等状态管理 - **电商系统**:订单状态管理(待付款、已付款、已发货等) - **审批流程**:不同审批阶段的状态转换 - **设备控制**:设备运行状态管理(启动、运行、停止、故障等) 状态模式通过将对象的状态封装成独立的类,使得对象可以在不同状态下表现出不同的行为,有效地解决了复杂条件判断带来的代码维护问题。 ## 策略模式 策略模式是一种行为型设计模式,其核心思想是**定义一系列算法,把它们一个个封装起来,并且使它们可以互相替换**。策略模式让算法的变化独立于使用算法的客户,使得算法可以独立于客户端而变化。 ### 核心概念 1. **Strategy(抽象策略类)** - 定义所有支持的算法的公共接口 - 上下文使用这个接口来调用具体的策略定义的算法 2. **ConcreteStrategy(具体策略类)** - 实现了Strategy接口的具体算法 - 每个具体策略类都封装了一种具体的算法实现 3. **Context(环境类)** - 持有一个Strategy类的引用 - 提供一个方法让客户端设置具体的策略 - 使用Strategy接口来调用具体的算法 ![10策略模式.png](img/04behavioral/10策略模式.png) ### 适用场景 - **在一个系统里面有许多类,它们之间的区别仅在于它们的行为**,使用策略模式可以动态地让一个对象在许多行为中选择一种行为 - **需要使用一个算法的不同变体** - **算法使用数据客户端不应该知道的数据** - **一个类定义了多种行为,并且这些行为在这个类的操作中以多个条件语句的形式出现** - **需要在运行时动态选择算法** ### 示例代码 - 排序策略 ```java import java.util.*; // 抽象策略类 interface SortStrategy { void sort(int[] array); String getStrategyName(); } // 具体策略类 - 冒泡排序 class BubbleSortStrategy implements SortStrategy { @Override public void sort(int[] array) { System.out.println("使用冒泡排序算法进行排序"); int n = array.length; for (int i = 0; i < n - 1; i++) { for (int j = 0; j < n - i - 1; j++) { if (array[j] > array[j + 1]) { // 交换元素 int temp = array[j]; array[j] = array[j + 1]; array[j + 1] = temp; } } } } @Override public String getStrategyName() { return "冒泡排序"; } } // 具体策略类 - 快速排序 class QuickSortStrategy implements SortStrategy { @Override public void sort(int[] array) { System.out.println("使用快速排序算法进行排序"); quickSort(array, 0, array.length - 1); } private void quickSort(int[] array, int low, int high) { if (low < high) { int pi = partition(array, low, high); quickSort(array, low, pi - 1); quickSort(array, pi + 1, high); } } private int partition(int[] array, int low, int high) { int pivot = array[high]; int i = (low - 1); for (int j = low; j < high; j++) { if (array[j] <= pivot) { i++; int temp = array[i]; array[i] = array[j]; array[j] = temp; } } int temp = array[i + 1]; array[i + 1] = array[high]; array[high] = temp; return i + 1; } @Override public String getStrategyName() { return "快速排序"; } } // 具体策略类 - 选择排序 class SelectionSortStrategy implements SortStrategy { @Override public void sort(int[] array) { System.out.println("使用选择排序算法进行排序"); int n = array.length; for (int i = 0; i < n - 1; i++) { int minIdx = i; for (int j = i + 1; j < n; j++) { if (array[j] < array[minIdx]) { minIdx = j; } } int temp = array[minIdx]; array[minIdx] = array[i]; array[i] = temp; } } @Override public String getStrategyName() { return "选择排序"; } } // 环境类 class SortContext { private SortStrategy strategy; public SortContext(SortStrategy strategy) { this.strategy = strategy; } public void setStrategy(SortStrategy strategy) { this.strategy = strategy; } public void executeSort(int[] array) { System.out.println("当前使用策略: " + strategy.getStrategyName()); strategy.sort(array); System.out.println("排序结果: " + Arrays.toString(array)); } } // 使用示例 public class SortStrategyExample { public static void main(String[] args) { int[] array1 = {64, 34, 25, 12, 22, 11, 90}; int[] array2 = {5, 2, 8, 1, 9, 3, 7}; int[] array3 = {100, 23, 45, 12, 8, 99, 34}; System.out.println("=== 策略模式 - 排序算法演示 ==="); System.out.println("原始数组1: " + Arrays.toString(array1)); System.out.println("原始数组2: " + Arrays.toString(array2)); System.out.println("原始数组3: " + Arrays.toString(array3)); System.out.println(); // 使用冒泡排序 SortContext context1 = new SortContext(new BubbleSortStrategy()); context1.executeSort(array1.clone()); System.out.println(); // 使用快速排序 SortContext context2 = new SortContext(new QuickSortStrategy()); context2.executeSort(array2.clone()); System.out.println(); // 使用选择排序 SortContext context3 = new SortContext(new SelectionSortStrategy()); context3.executeSort(array3.clone()); System.out.println(); // 动态切换策略 System.out.println("=== 动态切换策略演示 ==="); int[] array4 = {45, 23, 11, 89, 77, 98, 42}; SortContext dynamicContext = new SortContext(new BubbleSortStrategy()); System.out.println("原始数组4: " + Arrays.toString(array4)); dynamicContext.executeSort(array4.clone()); dynamicContext.setStrategy(new QuickSortStrategy()); dynamicContext.executeSort(array4.clone()); dynamicContext.setStrategy(new SelectionSortStrategy()); dynamicContext.executeSort(array4.clone()); } } ``` ### 更完整的示例 - 电商支付策略 ```java // 抽象策略类 interface PaymentStrategy { void pay(double amount); String getPaymentMethod(); } // 具体策略类 - 信用卡支付 class CreditCardStrategy implements PaymentStrategy { private String cardNumber; private String cardHolderName; private String cvv; private String expiryDate; public CreditCardStrategy(String cardNumber, String cardHolderName, String cvv, String expiryDate) { this.cardNumber = cardNumber; this.cardHolderName = cardHolderName; this.cvv = cvv; this.expiryDate = expiryDate; } @Override public void pay(double amount) { System.out.println("使用信用卡支付: ¥" + amount); System.out.println("信用卡号: " + maskCardNumber(cardNumber)); System.out.println("持卡人: " + cardHolderName); System.out.println("支付完成"); } @Override public String getPaymentMethod() { return "信用卡支付"; } private String maskCardNumber(String cardNumber) { if (cardNumber.length() > 4) { return "**** **** **** " + cardNumber.substring(cardNumber.length() - 4); } return cardNumber; } } // 具体策略类 - 支付宝支付 class AlipayStrategy implements PaymentStrategy { private String mobile; private String password; public AlipayStrategy(String mobile, String password) { this.mobile = mobile; this.password = password; } @Override public void pay(double amount) { System.out.println("使用支付宝支付: ¥" + amount); System.out.println("手机号: " + maskMobile(mobile)); System.out.println("正在跳转到支付宝..."); System.out.println("支付完成"); } @Override public String getPaymentMethod() { return "支付宝支付"; } private String maskMobile(String mobile) { if (mobile.length() > 7) { return mobile.substring(0, 3) + "****" + mobile.substring(7); } return mobile; } } // 具体策略类 - 微信支付 class WechatPayStrategy implements PaymentStrategy { private String wechatId; public WechatPayStrategy(String wechatId) { this.wechatId = wechatId; } @Override public void pay(double amount) { System.out.println("使用微信支付: ¥" + amount); System.out.println("微信号: " + maskWechatId(wechatId)); System.out.println("正在跳转到微信..."); System.out.println("支付完成"); } @Override public String getPaymentMethod() { return "微信支付"; } private String maskWechatId(String wechatId) { if (wechatId.length() > 4) { return wechatId.substring(0, 2) + "****" + wechatId.substring(wechatId.length() - 2); } return wechatId; } } // 具体策略类 - 现金支付 class CashStrategy implements PaymentStrategy { @Override public void pay(double amount) { System.out.println("使用现金支付: ¥" + amount); System.out.println("请准备相应现金"); System.out.println("支付完成"); } @Override public String getPaymentMethod() { return "现金支付"; } } // 环境类 - 购物车 class ShoppingCart { private List items; private PaymentStrategy paymentStrategy; public ShoppingCart() { this.items = new ArrayList<>(); } public void addItem(Item item) { items.add(item); } public void removeItem(Item item) { items.remove(item); } public double calculateTotal() { return items.stream().mapToDouble(Item::getPrice).sum(); } public void setPaymentStrategy(PaymentStrategy paymentStrategy) { this.paymentStrategy = paymentStrategy; } public void checkout() { if (paymentStrategy == null) { System.out.println("请选择支付方式"); return; } double total = calculateTotal(); System.out.println("=== 购物清单 ==="); for (Item item : items) { System.out.println(item.getName() + ": ¥" + item.getPrice()); } System.out.println("总计: ¥" + total); System.out.println(); paymentStrategy.pay(total); System.out.println("感谢您的购买!"); } } // 商品类 class Item { private String name; private double price; public Item(String name, double price) { this.name = name; this.price = price; } public String getName() { return name; } public double getPrice() { return price; } } // 使用示例 public class PaymentStrategyExample { public static void main(String[] args) { // 创建购物车 ShoppingCart cart = new ShoppingCart(); // 添加商品 cart.addItem(new Item("iPhone 15", 6999.00)); cart.addItem(new Item("AirPods Pro", 1999.00)); cart.addItem(new Item("保护壳", 99.00)); System.out.println("=== 电商支付策略演示 ==="); System.out.println(); // 使用信用卡支付 System.out.println("--- 使用信用卡支付 ---"); PaymentStrategy creditCard = new CreditCardStrategy("1234567890123456", "张三", "123", "12/25"); cart.setPaymentStrategy(creditCard); cart.checkout(); System.out.println(); // 使用支付宝支付 System.out.println("--- 使用支付宝支付 ---"); PaymentStrategy alipay = new AlipayStrategy("13800138000", "password123"); cart.setPaymentStrategy(alipay); cart.checkout(); System.out.println(); // 使用微信支付 System.out.println("--- 使用微信支付 ---"); PaymentStrategy wechatPay = new WechatPayStrategy("wechat_user_123456"); cart.setPaymentStrategy(wechatPay); cart.checkout(); System.out.println(); // 使用现金支付 System.out.println("--- 使用现金支付 ---"); PaymentStrategy cash = new CashStrategy(); cart.setPaymentStrategy(cash); cart.checkout(); } } ``` ### 优点 1. **算法可以自由切换** - 客户端可以在运行时选择不同的策略 - 策略之间可以灵活替换 2. **避免使用多重条件判断** - 将条件分支语句替换成策略模式,提高了代码的可维护性 - 消除了大量的if-else或switch-case语句 3. **扩展性良好** - 增加新的策略非常容易,只需要实现Strategy接口 - 符合开闭原则 4. **提高了算法的保密性和安全性** - 每种算法的具体实现都封装在对应的策略类中 - 客户端不需要知道算法的具体实现 5. **符合单一职责原则** - 每个策略类只负责一个算法 - 职责清晰,易于维护 ### 缺点 1. **客户端必须知道所有的策略类** - 客户端需要理解各个策略之间的差异 - 增加了客户端的使用复杂度 2. **会产生很多策略类** - 每一种算法都需要一个策略类 - 增加了系统的类数量 3. **所有策略类都需要对外暴露** - 客户端需要知道具体的策略类才能使用 - 违反了迪米特法则 4. **可能增加系统复杂度** - 对于简单的算法选择,策略模式可能显得过于复杂 ### 实际应用场景 - **排序算法选择**:根据数据规模选择不同的排序算法 - **支付方式选择**:支持多种支付方式(信用卡、支付宝、微信等) - **促销策略**:不同的折扣策略(满减、打折、赠品等) - **路径规划**:不同的路径搜索算法(最短路径、最快路径等) - **压缩算法**:支持多种压缩格式(ZIP、RAR、7Z等) - **数据库连接**:不同的数据库连接策略 - **缓存策略**:不同的缓存淘汰算法(LRU、FIFO等) - **日志记录**:不同的日志输出方式(文件、数据库、网络等) 策略模式通过将算法封装成独立的策略类,使得算法可以独立于客户端而变化,提供了极大的灵活性和可扩展性。它特别适用于算法需要动态切换或者有多种实现方式的场景。 ## 责任链模式 责任链模式是一种行为型设计模式,其核心思想是**为请求创建一个接收者对象的链,使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系**。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。 ### 核心概念 1. **Handler(抽象处理者)** - 定义一个处理请求的接口 - 实现后继链的设置和获取方法 - 声明处理请求的抽象方法 2. **ConcreteHandler(具体处理者)** - 实现抽象处理者定义的处理请求方法 - 处理自己能够处理的请求,否则将请求转发给后继者 - 每个具体处理者对应一种处理能力 3. **Client(客户端)** - 向链上的具体处理者对象提交请求 - 不需要知道具体哪个处理者会处理请求 ![11责任链模式.png](img/04behavioral/11责任链模式.png) ### 适用场景 - **有多个对象可以处理同一个请求,具体哪个对象处理该请求由运行时刻自动确定** - **在不明确指定接收者的情况下,向多个对象中的一个提交一个请求** - **可动态指定一组对象处理请求,客户端可以动态创建职责链** - **需要解耦请求的发送者和接收者** - **需要动态组合处理步骤的场景** ### 示例代码 - 请假审批系统 ```java // 抽象处理者 abstract class Approver { protected Approver successor; // 后继处理者 protected String name; // 处理者姓名 public Approver(String name) { this.name = name; } // 设置后继处理者 public void setSuccessor(Approver successor) { this.successor = successor; } // 处理请求的抽象方法 public abstract void processRequest(LeaveRequest request); } // 具体处理者 - 班主任 class ClassAdviser extends Approver { public ClassAdviser(String name) { super(name); } @Override public void processRequest(LeaveRequest request) { if (request.getDays() <= 3) { System.out.println("班主任 " + name + " 审批了 " + request.getName() + " 的请假申请,天数:" + request.getDays() + " 天,理由:" + request.getReason()); } else { System.out.println("班主任 " + name + " 无法审批 " + request.getName() + " 的请假申请,天数:" + request.getDays() + " 天,已提交上级审批"); if (successor != null) { successor.processRequest(request); } } } } // 具体处理者 - 系主任 class DepartmentHead extends Approver { public DepartmentHead(String name) { super(name); } @Override public void processRequest(LeaveRequest request) { if (request.getDays() <= 7) { System.out.println("系主任 " + name + " 审批了 " + request.getName() + " 的请假申请,天数:" + request.getDays() + " 天,理由:" + request.getReason()); } else { System.out.println("系主任 " + name + " 无法审批 " + request.getName() + " 的请假申请,天数:" + request.getDays() + " 天,已提交上级审批"); if (successor != null) { successor.processRequest(request); } } } } // 具体处理者 - 院长 class Dean extends Approver { public Dean(String name) { super(name); } @Override public void processRequest(LeaveRequest request) { if (request.getDays() <= 15) { System.out.println("院长 " + name + " 审批了 " + request.getName() + " 的请假申请,天数:" + request.getDays() + " 天,理由:" + request.getReason()); } else { System.out.println("院长 " + name + " 无法审批 " + request.getName() + " 的请假申请,天数:" + request.getDays() + " 天,已提交上级审批"); if (successor != null) { successor.processRequest(request); } } } } // 具体处理者 - 校长 class President extends Approver { public President(String name) { super(name); } @Override public void processRequest(LeaveRequest request) { if (request.getDays() <= 30) { System.out.println("校长 " + name + " 审批了 " + request.getName() + " 的请假申请,天数:" + request.getDays() + " 天,理由:" + request.getReason()); } else { System.out.println("校长 " + name + " 无法审批 " + request.getName() + " 的请假申请,天数:" + request.getDays() + " 天,超过审批权限"); System.out.println("请假申请被拒绝!"); } } } // 请求类 - 请假申请 class LeaveRequest { private String name; // 申请人姓名 private int days; // 请假天数 private String reason; // 请假原因 public LeaveRequest(String name, int days, String reason) { this.name = name; this.days = days; this.reason = reason; } public String getName() { return name; } public int getDays() { return days; } public String getReason() { return reason; } } // 使用示例 public class LeaveApprovalExample { public static void main(String[] args) { // 创建处理者对象 Approver classAdviser = new ClassAdviser("张老师"); Approver departmentHead = new DepartmentHead("李主任"); Approver dean = new Dean("王院长"); Approver president = new President("陈校长"); // 设置职责链 classAdviser.setSuccessor(departmentHead); departmentHead.setSuccessor(dean); dean.setSuccessor(president); System.out.println("=== 请假审批系统演示 ==="); System.out.println(); // 创建不同的请假申请 LeaveRequest request1 = new LeaveRequest("小明", 2, "生病"); System.out.println("申请1: " + request1.getName() + " 请假 " + request1.getDays() + " 天,原因:" + request1.getReason()); classAdviser.processRequest(request1); System.out.println(); LeaveRequest request2 = new LeaveRequest("小红", 5, "参加比赛"); System.out.println("申请2: " + request2.getName() + " 请假 " + request2.getDays() + " 天,原因:" + request2.getReason()); classAdviser.processRequest(request2); System.out.println(); LeaveRequest request3 = new LeaveRequest("小刚", 10, "家庭事务"); System.out.println("申请3: " + request3.getName() + " 请假 " + request3.getDays() + " 天,原因:" + request3.getReason()); classAdviser.processRequest(request3); System.out.println(); LeaveRequest request4 = new LeaveRequest("小丽", 20, "出国旅游"); System.out.println("申请4: " + request4.getName() + " 请假 " + request4.getDays() + " 天,原因:" + request4.getReason()); classAdviser.processRequest(request4); System.out.println(); LeaveRequest request5 = new LeaveRequest("小强", 40, "长期休假"); System.out.println("申请5: " + request5.getName() + " 请假 " + request5.getDays() + " 天,原因:" + request5.getReason()); classAdviser.processRequest(request5); } } ``` ### 更完整的示例 - 日志处理系统 ```java import java.util.logging.Level; // 抽象处理者 - 日志处理器 abstract class Logger { public static int DEBUG = 1; public static int INFO = 2; public static int ERROR = 3; protected int level; protected Logger nextLogger; public Logger(int level) { this.level = level; } // 设置下一个处理器 public void setNextLogger(Logger nextLogger) { this.nextLogger = nextLogger; } // 处理日志请求 public void logMessage(int level, String message) { if (this.level <= level) { write(message); } if (nextLogger != null) { nextLogger.logMessage(level, message); } } // 抽象方法,由具体处理器实现 abstract protected void write(String message); } // 具体处理者 - 控制台日志处理器 class ConsoleLogger extends Logger { public ConsoleLogger(int level) { super(level); } @Override protected void write(String message) { System.out.println("控制台日志: " + message); } } // 具体处理者 - 文件日志处理器 class FileLogger extends Logger { public FileLogger(int level) { super(level); } @Override protected void write(String message) { System.out.println("文件日志: " + message); } } // 具体处理者 - 错误日志处理器 class ErrorLogger extends Logger { public ErrorLogger(int level) { super(level); } @Override protected void write(String message) { System.out.println("错误日志: " + message); } } // 使用示例 public class LoggerExample { private static Logger getChainOfLoggers() { Logger errorLogger = new ErrorLogger(Logger.ERROR); Logger fileLogger = new FileLogger(Logger.INFO); Logger consoleLogger = new ConsoleLogger(Logger.DEBUG); // 构建责任链: DEBUG -> INFO -> ERROR consoleLogger.setNextLogger(fileLogger); fileLogger.setNextLogger(errorLogger); return consoleLogger; } public static void main(String[] args) { Logger loggerChain = getChainOfLoggers(); System.out.println("=== 日志处理系统演示 ==="); System.out.println(); System.out.println("1. 输出DEBUG级别日志:"); loggerChain.logMessage(Logger.DEBUG, "这是调试信息"); System.out.println(); System.out.println("2. 输出INFO级别日志:"); loggerChain.logMessage(Logger.INFO, "这是普通信息"); System.out.println(); System.out.println("3. 输出ERROR级别日志:"); loggerChain.logMessage(Logger.ERROR, "这是错误信息"); System.out.println(); System.out.println("4. 输出多条日志:"); loggerChain.logMessage(Logger.DEBUG, "调试信息1"); loggerChain.logMessage(Logger.INFO, "普通信息1"); loggerChain.logMessage(Logger.ERROR, "错误信息1"); } } ``` ### 更高级的示例 - Web请求过滤器 ```java // 请求类 class Request { private String url; private String method; private String userAgent; private String ip; public Request(String url, String method, String userAgent, String ip) { this.url = url; this.method = method; this.userAgent = userAgent; this.ip = ip; } // Getters public String getUrl() { return url; } public String getMethod() { return method; } public String getUserAgent() { return userAgent; } public String getIp() { return ip; } @Override public String toString() { return String.format("Request{url='%s', method='%s', userAgent='%s', ip='%s'}", url, method, userAgent, ip); } } // 响应类 class Response { private int statusCode; private String body; public Response() { this.statusCode = 200; this.body = "OK"; } public void setStatus(int statusCode, String body) { this.statusCode = statusCode; this.body = body; } public int getStatusCode() { return statusCode; } public String getBody() { return body; } @Override public String toString() { return String.format("Response{statusCode=%d, body='%s'}", statusCode, body); } } // 抽象处理者 - 过滤器 abstract class Filter { protected Filter nextFilter; public void setNext(Filter nextFilter) { this.nextFilter = nextFilter; } public void doFilter(Request request, Response response) { // 执行当前过滤器的处理逻辑 boolean continueChain = process(request, response); // 如果当前过滤器允许继续处理,且存在下一个过滤器,则调用下一个过滤器 if (continueChain && nextFilter != null) { nextFilter.doFilter(request, response); } } // 抽象方法,由具体过滤器实现 public abstract boolean process(Request request, Response response); } // 具体处理者 - IP过滤器 class IPFilter extends Filter { @Override public boolean process(Request request, Response response) { String ip = request.getIp(); System.out.println("IP过滤器检查IP: " + ip); // 黑名单检查 if ("192.168.1.100".equals(ip)) { System.out.println("IP被禁止访问: " + ip); response.setStatus(403, "Forbidden: IP blocked"); return false; // 阻止继续处理 } System.out.println("IP检查通过: " + ip); return true; // 允许继续处理 } } // 具体处理者 - 用户代理过滤器 class UserAgentFilter extends Filter { @Override public boolean process(Request request, Response response) { String userAgent = request.getUserAgent(); System.out.println("UserAgent过滤器检查: " + userAgent); // 禁止某些爬虫 if (userAgent != null && userAgent.contains("BadBot")) { System.out.println("禁止恶意爬虫: " + userAgent); response.setStatus(403, "Forbidden: Bad bot detected"); return false; // 阻止继续处理 } System.out.println("UserAgent检查通过: " + userAgent); return true; // 允许继续处理 } } // 具体处理者 - 方法过滤器 class MethodFilter extends Filter { @Override public boolean process(Request request, Response response) { String method = request.getMethod(); System.out.println("方法过滤器检查HTTP方法: " + method); // 只允许GET和POST方法 if (!("GET".equals(method) || "POST".equals(method))) { System.out.println("不支持的HTTP方法: " + method); response.setStatus(405, "Method Not Allowed"); return false; // 阻止继续处理 } System.out.println("HTTP方法检查通过: " + method); return true; // 允许继续处理 } } // 具体处理者 - URL过滤器 class URLFilter extends Filter { @Override public boolean process(Request request, Response response) { String url = request.getUrl(); System.out.println("URL过滤器检查URL: " + url); // 禁止访问敏感目录 if (url.startsWith("/admin/") || url.startsWith("/config/")) { System.out.println("禁止访问敏感URL: " + url); response.setStatus(403, "Forbidden: Access to sensitive resource denied"); return false; // 阻止继续处理 } System.out.println("URL检查通过: " + url); return true; // 允许继续处理 } } // 过滤器链管理器 class FilterChain { private Filter head; private Filter tail; public void addFilter(Filter filter) { if (head == null) { head = filter; tail = filter; } else { tail.setNext(filter); tail = filter; } } public void doFilter(Request request, Response response) { if (head != null) { head.doFilter(request, response); } } } // 使用示例 public class WebFilterExample { public static void main(String[] args) { // 创建过滤器链 FilterChain filterChain = new FilterChain(); // 添加过滤器(按照检查顺序) filterChain.addFilter(new IPFilter()); filterChain.addFilter(new UserAgentFilter()); filterChain.addFilter(new MethodFilter()); filterChain.addFilter(new URLFilter()); System.out.println("=== Web请求过滤器演示 ==="); System.out.println(); // 测试正常的请求 System.out.println("--- 正常请求测试 ---"); Request normalRequest = new Request("/index.html", "GET", "Mozilla/5.0 Chrome", "192.168.1.1"); Response normalResponse = new Response(); System.out.println("请求: " + normalRequest); filterChain.doFilter(normalRequest, normalResponse); System.out.println("响应: " + normalResponse); System.out.println(); // 测试被IP过滤器拦截的请求 System.out.println("--- IP黑名单测试 ---"); Request blockedIPRequest = new Request("/index.html", "GET", "Mozilla/5.0 Chrome", "192.168.1.100"); Response blockedIPResponse = new Response(); System.out.println("请求: " + blockedIPRequest); filterChain.doFilter(blockedIPRequest, blockedIPResponse); System.out.println("响应: " + blockedIPResponse); System.out.println(); // 测试被UserAgent过滤器拦截的请求 System.out.println("--- 恶意爬虫测试 ---"); Request badBotRequest = new Request("/index.html", "GET", "BadBot Crawler", "192.168.1.50"); Response badBotResponse = new Response(); System.out.println("请求: " + badBotRequest); filterChain.doFilter(badBotRequest, badBotResponse); System.out.println("响应: " + badBotResponse); System.out.println(); // 测试被方法过滤器拦截的请求 System.out.println("--- 不支持的方法测试 ---"); Request unsupportedMethodRequest = new Request("/index.html", "DELETE", "Mozilla/5.0 Chrome", "192.168.1.2"); Response unsupportedMethodResponse = new Response(); System.out.println("请求: " + unsupportedMethodRequest); filterChain.doFilter(unsupportedMethodRequest, unsupportedMethodResponse); System.out.println("响应: " + unsupportedMethodResponse); System.out.println(); // 测试被URL过滤器拦截的请求 System.out.println("--- 敏感URL访问测试 ---"); Request sensitiveURLRequest = new Request("/admin/users", "GET", "Mozilla/5.0 Chrome", "192.168.1.3"); Response sensitiveURLResponse = new Response(); System.out.println("请求: " + sensitiveURLRequest); filterChain.doFilter(sensitiveURLRequest, sensitiveURLResponse); System.out.println("响应: " + sensitiveURLResponse); } } ``` ### 优点 1. **降低耦合度** - 将请求的发送者和接收者解耦 - 发送者不需要知道具体的接收者是谁 2. **增强了给对象指派职责的灵活性** - 可以在运行时动态地改变和组织责任链 - 可以很方便地增加或删除处理者 3. **简化了对象之间的连接** - 每个对象只需保持一个指向其后继者的引用 - 不需保持它所有的候选接收者的引用 4. **增加了新的请求处理类很方便** - 只需要实现处理接口并正确设置后继者即可 5. **符合开闭原则** - 增加新的具体处理者无须修改原有代码 ### 缺点 1. **不能保证请求一定被接收** - 请求可能得不到处理,既没有明确的接收者,也没有默认的处理者 2. **系统性能会受到一定影响** - 大量的条件判断可能会影响系统性能 - 责任链过长时会影响处理效率 3. **调试困难** - 责任链较长时,调试较为困难 - 不容易观察运行时的特征 4. **可能造成循环调用** - 如果责任链配置不当,可能导致循环调用 ### 实际应用场景 - **Web请求处理**:Servlet过滤器链、Spring Security安全过滤器 - **异常处理**:Java异常处理机制 - **日志处理**:不同级别的日志处理器 - **审批流程**:OA系统中的多级审批 - **事件处理**:GUI中的事件传播机制 - **拦截器模式**:MyBatis插件、Spring AOP - **命令处理**:游戏中的命令解析和执行 - **数据验证**:表单数据的多层验证 责任链模式通过将请求的处理者组织成一条链,使得请求可以沿着链传递,直到被处理或到达链尾。这种模式非常适合处理具有层级关系或多步骤处理的场景。