3107 lines
80 KiB
Markdown
3107 lines
80 KiB
Markdown
# 设计模式
|
||
|
||
设计模式是对许多业务和算法的抽象,因此学习起来具有一定的难度。短时间内掌握是不可能的,需要通过不断的实践和理解来积累经验。对于已经在职场上工作,但后期才开始学习设计模式的人来说,可能会面临更多的挑战。
|
||
|
||
在学习设计模式时,很多概念趋于理论化,且种类繁多(设计模式总共有23种),如果没有进行系统的梳理,可能很难直接应用到实际场景中。
|
||
|
||
设计模式中的抽象类通常是接口或抽象类,这些类的实现会根据具体的业务需求进行调整,因而不一定是唯一的实现方式。
|
||
|
||
在我学习过程中,我试图将所学的内容总结下来,但由于篇幅有限,无法一一列举所有场景,只能举出一些常见的例子。
|
||
|
||
---
|
||
|
||
## 工厂模式---创建型
|
||
|
||
### 工厂模式(Factory Pattern)介绍
|
||
|
||
工厂模式属于创建型设计模式,主要用于通过定义一个接口来创建对象,但让子类决定实例化哪一个类。通过这种方式,工厂模式将对象的创建与使用分离,从而解耦了客户端与具体类的依赖关系。
|
||
|
||
工厂模式的核心思想是:**让子类决定具体要创建哪一个产品,而不是直接在客户端代码中硬编码要使用哪个类**。
|
||
|
||
### 工厂模式的主要角色
|
||
|
||
1. **产品接口(Product)**:通常是一个接口或者抽象类,定义了具体产品的公共方法。
|
||
2. **具体产品(Concrete Product)**:实现了产品接口的具体类,代表不同的产品。
|
||
3. **工厂接口(Creator)**:通常是一个抽象类或接口,定义了一个工厂方法用于创建产品。
|
||
4. **具体工厂(Concrete Creator)**:实现了工厂接口的具体类,负责创建具体的产品对象。
|
||
|
||
### 工厂模式的类型
|
||
|
||
1. **简单工厂模式(Simple Factory)**:通过工厂类中的一个方法,根据传入的参数决定返回哪种具体的产品对象。
|
||
2. **工厂方法模式(Factory Method)**:通过一个工厂接口或者抽象类来定义创建产品的工厂方法,让子类决定创建哪个具体产品。
|
||
3. **抽象工厂模式(Abstract Factory)**:提供一个创建一系列相关或相互依赖对象的接口,而无需指定具体类。
|
||
|
||
### 简单工厂模式示例(Java)
|
||
|
||
```java
|
||
// 产品接口
|
||
public interface Product {
|
||
void create();
|
||
}
|
||
|
||
// 具体产品A
|
||
public class ProductA implements Product {
|
||
@Override
|
||
public void create() {
|
||
System.out.println("Product A created.");
|
||
}
|
||
}
|
||
|
||
// 具体产品B
|
||
public class ProductB implements Product {
|
||
@Override
|
||
public void create() {
|
||
System.out.println("Product B created.");
|
||
}
|
||
}
|
||
|
||
// 工厂类
|
||
public class ProductFactory {
|
||
// 简单工厂方法,根据输入参数创建不同的产品
|
||
public static Product createProduct(String productType) {
|
||
if ("A".equals(productType)) {
|
||
return new ProductA();
|
||
} else if ("B".equals(productType)) {
|
||
return new ProductB();
|
||
}
|
||
throw new IllegalArgumentException("Unknown product type");
|
||
}
|
||
}
|
||
|
||
// 客户端代码
|
||
public class Client {
|
||
public static void main(String[] args) {
|
||
Product productA = ProductFactory.createProduct("A");
|
||
productA.create();
|
||
|
||
Product productB = ProductFactory.createProduct("B");
|
||
productB.create();
|
||
}
|
||
}
|
||
```
|
||
|
||
### 优点
|
||
|
||
1. **降低耦合度**:工厂模式将对象的创建过程与使用过程分开,客户端不需要了解具体的创建过程,从而降低了耦合度。
|
||
2. **易于扩展**:可以通过新增具体产品类和工厂方法来扩展系统,不需要修改现有代码,符合开闭原则(OCP)。
|
||
3. **提高代码的可维护性**:当需要修改创建产品的逻辑时,只需修改工厂类,不影响客户端代码。
|
||
|
||
### 缺点
|
||
|
||
1. **增加类的数量**:引入了工厂类、产品接口和多个具体产品类,可能导致类的数量增加,系统变得复杂。
|
||
2. **难以理解和维护**:对于一些简单的应用程序,使用工厂模式可能会使得设计过于复杂,反而增加了理解和维护的难度。
|
||
|
||
---
|
||
|
||
## 单例模式---创建型
|
||
|
||
### 懒汉模式
|
||
|
||
#### 双重检查锁定(DCL)
|
||
|
||
```java
|
||
public class Singleton {
|
||
private static volatile Singleton instance;
|
||
|
||
private Singleton() {
|
||
// 构造函数私有化
|
||
}
|
||
|
||
public static Singleton getInstance() {
|
||
if (instance == null) { // 第一次检查
|
||
synchronized (Singleton.class) {
|
||
if (instance == null) { // 第二次检查
|
||
instance = new Singleton();
|
||
}
|
||
}
|
||
}
|
||
return instance;
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 静态内部类方式
|
||
|
||
利用 **静态内部类**(饿汉式)的特性来实现懒汉模式,并且可以保证线程安全。这种方式只有在调用 `getInstance()` 时才会加载内部类,从而实现懒加载。
|
||
|
||
```java
|
||
public class Singleton {
|
||
private Singleton() {
|
||
// 构造函数私有化
|
||
}
|
||
|
||
private static class SingletonHolder {
|
||
private static final Singleton INSTANCE = new Singleton();
|
||
}
|
||
|
||
public static Singleton getInstance() {
|
||
return SingletonHolder.INSTANCE;
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 适用场景
|
||
|
||
- 如果单例对象比较重,且只在程序中某些特定情况下才使用,懒汉模式可以带来性能优势。
|
||
- 在低并发环境或单线程环境下,懒汉模式使用较为简单,不会有多线程安全问题。
|
||
- 对于高并发且需要频繁访问单例的场景,推荐使用**静态内部类**或**饿汉模式**来避免懒汉模式可能带来的性能问题。
|
||
|
||
- **优点**:
|
||
1. 延迟加载,节省资源。
|
||
2. 内存优化,只有在需要时才实例化。
|
||
3. 减少不必要的初始化开销。
|
||
- **缺点**:
|
||
1. 传统懒汉模式线程不安全(多个线程可能会创建多个实例)。
|
||
2. 使用同步机制会有性能开销,特别是在多线程环境下。
|
||
3. 代码复杂性较高,容易引入错误。
|
||
4. 不适合高并发场景,特别是频繁访问时会影响性能。
|
||
|
||
### 饿汉模式
|
||
|
||
**饿汉模式**(Eager Initialization)是单例模式的一种实现方式,在该方式中,单例实例在类加载时就已经创建完成,而不是在首次使用时才创建。换句话说,**饿汉模式**
|
||
的单例实例在类被加载时就会立即初始化,确保了单例模式的唯一性。
|
||
|
||
```java
|
||
public class Singleton {
|
||
|
||
// 在类加载时就初始化单例对象
|
||
private static final Singleton INSTANCE = new Singleton();
|
||
|
||
// 私有构造函数,防止外部通过 new 创建实例
|
||
private Singleton() {
|
||
}
|
||
|
||
// 提供全局访问点
|
||
public static Singleton getInstance() {
|
||
return INSTANCE;
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 适用场景
|
||
|
||
- **简单应用**:适合没有延迟初始化需求的小型应用,或者单例对象的创建非常轻量,不会影响系统性能的场景。
|
||
- **实例化不耗费太多资源**:如果单例对象的初始化过程非常轻量级且无须延迟初始化,可以使用饿汉模式。
|
||
- **类加载顺序固定**:如果不在乎单例对象在启动时是否初始化,且单例对象的初始化过程没有严重性能损失,可以选择饿汉模式。
|
||
|
||
- **优点**:简单、线程安全、性能高(没有锁机制)、实现方便。
|
||
- **缺点**:不支持延迟加载、可能会浪费资源(如果单例对象不常用时)。
|
||
|
||
饿汉模式是单例模式中最简单的实现方式,适用于大多数情况下单例对象的创建开销较小,且不需要延迟初始化的场景。如果单例对象的创建非常轻量且不依赖于后期加载时的资源,饿汉模式是一个不错的选择。
|
||
|
||
### 枚举类型实现
|
||
|
||
**枚举类型实现单例模式**(Enum Singleton)是实现单例模式的另一种方式,优点是更加简洁、可靠,并且避免了许多常见的单例实现方式(如懒汉模式和饿汉模式)可能出现的问题。使用枚举类型的单例实现方式自
|
||
**Java 5** 引入以来,已经成为了最推荐的单例模式实现方式之一。
|
||
|
||
**当你不需要懒加载或延迟初始化时,使用枚举实现单例模式是最理想的选择。**
|
||
|
||
```java
|
||
public enum Singleton {
|
||
|
||
// 唯一实例
|
||
INSTANCE;
|
||
|
||
// 可以添加其他的方法
|
||
public void someMethod() {
|
||
System.out.println("This is a singleton instance method.");
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 使用示例
|
||
|
||
```java
|
||
public class Main {
|
||
public static void main(String[] args) {
|
||
// 获取单例对象
|
||
Singleton singleton = Singleton.INSTANCE;
|
||
|
||
// 调用单例方法
|
||
singleton.someMethod();
|
||
}
|
||
}
|
||
```
|
||
|
||
## 原型模式---创建型
|
||
|
||
![image-20250202214232289](./images/设计模式-v2/image-20250202214232289.png)
|
||
|
||
需要三个角色:抽象原型类(Abstract Prototype)、具体原型类(Concrete Prototype)、访问类(Client)
|
||
|
||
### 简单示例
|
||
|
||
提示:需要做深克隆,当类中还存在另一个类时
|
||
|
||
#### 错误示例代码
|
||
|
||
当我们对school对象进行设置时,对`resume1`进行设置结果`resume`也发生了改变。需要修改`Resume`类中的`clone`方法
|
||
|
||
```java
|
||
public class Prototype {
|
||
public static void main(String[] args) {
|
||
Resume resume = new Resume();
|
||
resume.name = "Bunny";
|
||
resume.position = "架构师";
|
||
resume.salary = 15000;
|
||
|
||
School school = new School();
|
||
school.schoolName = "江南大学";
|
||
school.time = "2025年2月2日21:38:07";
|
||
resume.school = school;
|
||
System.out.println(resume);
|
||
|
||
Resume resume1 = resume.clone();
|
||
resume1.salary = 19000;
|
||
resume1.school.schoolName = "清华大学";
|
||
System.out.println(resume1);
|
||
|
||
Resume resume2 = resume.clone();
|
||
resume2.salary = 20000;
|
||
System.out.println(resume2);
|
||
|
||
System.out.println(resume1 == resume2);// false
|
||
System.out.println(resume1.school == resume2.school);// true
|
||
}
|
||
|
||
@Data
|
||
static class Resume implements Cloneable {
|
||
private String name;
|
||
private String position;
|
||
private Integer salary;
|
||
private School school;
|
||
|
||
@Override
|
||
public Resume clone() {
|
||
try {
|
||
return (Resume) super.clone();
|
||
} catch (CloneNotSupportedException e) {
|
||
throw new AssertionError();
|
||
}
|
||
}
|
||
}
|
||
|
||
@Data
|
||
static class School implements Cloneable {
|
||
private String schoolName;
|
||
private String time;
|
||
|
||
@Override
|
||
public School clone() {
|
||
try {
|
||
return (School) super.clone();
|
||
} catch (CloneNotSupportedException e) {
|
||
throw new AssertionError();
|
||
}
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 运行结果:
|
||
|
||
```java
|
||
Prototype.Resume(name=Bunny, position=架构师, salary=15000, school=Prototype.School(schoolName=江南大学, time=2025年2月2日21:38:07))
|
||
Prototype.Resume(name=Bunny, position=架构师, salary=19000, school=Prototype.School(schoolName=清华大学, time=2025年2月2日21:38:07))
|
||
Prototype.Resume(name=Bunny, position=架构师, salary=20000, school=Prototype.School(schoolName=清华大学, time=2025年2月2日21:38:07))
|
||
false
|
||
true
|
||
```
|
||
|
||
#### 正确示例代码
|
||
|
||
##### 修改`conle`
|
||
|
||
```java
|
||
@Data
|
||
static class Resume implements Cloneable {
|
||
private String name;
|
||
private String position;
|
||
private Integer salary;
|
||
private School school;
|
||
|
||
@Override
|
||
public Resume clone() {
|
||
Resume resume = null;
|
||
try {
|
||
resume = (Resume) super.clone();
|
||
if (school != null) {
|
||
resume.school = school.clone();
|
||
}
|
||
} catch (CloneNotSupportedException e) {
|
||
throw new AssertionError();
|
||
}
|
||
|
||
return resume;
|
||
}
|
||
}
|
||
```
|
||
|
||
##### 示例
|
||
|
||
```java
|
||
public class Prototype {
|
||
public static void main(String[] args) {
|
||
Resume resume = new Resume();
|
||
resume.name = "Bunny";
|
||
resume.position = "架构师";
|
||
resume.salary = 15000;
|
||
|
||
School school = new School();
|
||
school.schoolName = "江南大学";
|
||
school.time = "2025年2月2日21:38:07";
|
||
resume.school = school;
|
||
System.out.println(resume);
|
||
|
||
Resume resume1 = resume.clone();
|
||
resume1.salary = 19000;
|
||
resume1.school.schoolName = "清华大学";
|
||
System.out.println(resume1);
|
||
|
||
Resume resume2 = resume.clone();
|
||
resume2.salary = 20000;
|
||
System.out.println(resume2);
|
||
|
||
System.out.println(resume1 == resume2);// false
|
||
System.out.println(resume1.school == resume2.school);// false
|
||
}
|
||
|
||
@Data
|
||
static class Resume implements Cloneable {
|
||
private String name;
|
||
private String position;
|
||
private Integer salary;
|
||
private School school;
|
||
|
||
@Override
|
||
public Resume clone() {
|
||
Resume resume = null;
|
||
try {
|
||
resume = (Resume) super.clone();
|
||
if (school != null) {
|
||
resume.school = school.clone();
|
||
}
|
||
} catch (CloneNotSupportedException e) {
|
||
throw new AssertionError();
|
||
}
|
||
|
||
return resume;
|
||
}
|
||
}
|
||
|
||
@Data
|
||
static class School implements Cloneable {
|
||
private String schoolName;
|
||
private String time;
|
||
|
||
@Override
|
||
public School clone() {
|
||
try {
|
||
return (School) super.clone();
|
||
} catch (CloneNotSupportedException e) {
|
||
throw new AssertionError();
|
||
}
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 运行结果:
|
||
|
||
```java
|
||
Prototype.Resume(name=Bunny, position=架构师, salary=15000, school=Prototype.School(schoolName=江南大学, time=2025年2月2日21:38:07))
|
||
Prototype.Resume(name=Bunny, position=架构师, salary=19000, school=Prototype.School(schoolName=清华大学, time=2025年2月2日21:38:07))
|
||
Prototype.Resume(name=Bunny, position=架构师, salary=20000, school=Prototype.School(schoolName=江南大学, time=2025年2月2日21:38:07))
|
||
false
|
||
false
|
||
```
|
||
|
||
---
|
||
|
||
## 建造者模式
|
||
|
||
![image-20250201203116885](./images/设计模式-v2/image-20250201203116885.png)
|
||
|
||
### 简单示例
|
||
|
||
比如我们要构建一个复杂的 `Computer`(计算机)对象。我们可以定义一个 `ComputerBuilder`,它将按顺序设置计算机的 CPU、内存、硬盘等组件,最后得到一个完整的 `Computer` 对象。
|
||
|
||
#### 代码示例
|
||
|
||
```java
|
||
public class CommandDemo {
|
||
public static void main(String[] args) {
|
||
ConcreteLowComputerBuilder concreteLowComputerBuilder = new ConcreteLowComputerBuilder();
|
||
Director director = new Director(concreteLowComputerBuilder);
|
||
director.constructComputer();
|
||
System.out.println(concreteLowComputerBuilder.getComputer());
|
||
|
||
System.out.println("\n-----------------分割线-----------------\n");
|
||
|
||
ConcreteHighComputerBuilder concreteHighComputerBuilder = new ConcreteHighComputerBuilder();
|
||
director = new Director(concreteHighComputerBuilder);
|
||
director.constructComputer();
|
||
System.out.println(concreteHighComputerBuilder.getComputer());
|
||
}
|
||
|
||
// 构建产品接口
|
||
interface ComputerBuilder {
|
||
|
||
/**
|
||
* 构建 CPU 方法
|
||
*/
|
||
void buildCPU();
|
||
|
||
/**
|
||
* 构建 RAM 方法
|
||
*/
|
||
void buildRAM();
|
||
|
||
/**
|
||
* 构建 磁盘 方法
|
||
*/
|
||
void buildHardDrive();
|
||
|
||
/**
|
||
* 返回产品
|
||
*
|
||
* @return Computer
|
||
*/
|
||
Computer getComputer();
|
||
}
|
||
|
||
// 产品类
|
||
@Data
|
||
static class Computer {
|
||
private String CPU;
|
||
private String RAM;
|
||
private String hardDrive;
|
||
}
|
||
|
||
// 构建低端产品
|
||
static class ConcreteLowComputerBuilder implements ComputerBuilder {
|
||
private final Computer computer = new Computer();
|
||
|
||
/**
|
||
* 构建 CPU 方法
|
||
*/
|
||
@Override
|
||
public void buildCPU() {
|
||
computer.setCPU("Low CPU");
|
||
}
|
||
|
||
/**
|
||
* 构建 RAM 方法
|
||
*/
|
||
@Override
|
||
public void buildRAM() {
|
||
computer.setRAM("Low RAM");
|
||
}
|
||
|
||
/**
|
||
* 构建 磁盘 方法
|
||
*/
|
||
@Override
|
||
public void buildHardDrive() {
|
||
computer.setHardDrive("Low Driver");
|
||
}
|
||
|
||
/**
|
||
* 返回产品
|
||
*
|
||
* @return Computer
|
||
*/
|
||
@Override
|
||
public Computer getComputer() {
|
||
return computer;
|
||
}
|
||
}
|
||
|
||
// 构建高端产品
|
||
static class ConcreteHighComputerBuilder implements ComputerBuilder {
|
||
private final Computer computer = new Computer();
|
||
|
||
/**
|
||
* 构建 CPU 方法
|
||
*/
|
||
@Override
|
||
public void buildCPU() {
|
||
computer.setCPU("High CPU");
|
||
}
|
||
|
||
/**
|
||
* 构建 RAM 方法
|
||
*/
|
||
@Override
|
||
public void buildRAM() {
|
||
computer.setRAM("High RAM");
|
||
}
|
||
|
||
/**
|
||
* 构建 磁盘 方法
|
||
*/
|
||
@Override
|
||
public void buildHardDrive() {
|
||
computer.setHardDrive("High Driver");
|
||
}
|
||
|
||
/**
|
||
* 返回产品
|
||
*
|
||
* @return Computer
|
||
*/
|
||
@Override
|
||
public Computer getComputer() {
|
||
return computer;
|
||
}
|
||
}
|
||
|
||
// 构建者
|
||
public static class Director {
|
||
private final ComputerBuilder builder;
|
||
|
||
public Director(ComputerBuilder builder) {
|
||
this.builder = builder;
|
||
}
|
||
|
||
public void constructComputer() {
|
||
builder.buildCPU();
|
||
builder.buildRAM();
|
||
builder.buildHardDrive();
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 运行结果:
|
||
|
||
```java
|
||
CommandDemo.Computer(CPU=Low CPU, RAM=Low RAM, hardDrive=Low Driver)
|
||
|
||
-----------------分割线-----------------
|
||
|
||
CommandDemo.Computer(CPU=High CPU, RAM=High RAM, hardDrive=High Driver)
|
||
```
|
||
|
||
---
|
||
|
||
## 装饰者模式---结构型
|
||
|
||
一共有四个角色。
|
||
|
||
- 抽象组件:一般是最原始、最基础的对象。
|
||
- 具体组件:一般是最原始最基础的实现对象,可以有多个(只是数量不多),可以大致看下`InputStream`UML结构图。
|
||
- 装饰角色:继承或者实现**抽象组件**这是最关键的地方。
|
||
- 具体装饰角色:可以有多个实现或者继承**装饰角色**。
|
||
|
||
### 简单示例
|
||
|
||
需要做一个抽象的相机功能,相机包含拍照功能(这是肯定的),之后随着业务需求要求相机有美颜功能,在这之后还要有滤镜功能,客户还需要延迟摄影功能。
|
||
|
||
![image-20250201185356903](./images/设计模式-v2/image-20250201185356903.png)
|
||
|
||
#### 代码实现
|
||
|
||
1. 需要定义根组件(Component)
|
||
|
||
2. 制作最原始的拍照功能,实现根组件
|
||
3. 制作延迟摄影,实现根组件
|
||
4. 作为相机之外的功能(美颜),需要定义装饰角色方便为以后的组件进行扩展
|
||
5. 继承或者实现(装饰者角色),完成美颜
|
||
6. 继承或者实现(装饰者角色),完成滤镜
|
||
|
||
```java
|
||
public class CameraDemo {
|
||
public static void main(String[] args) {
|
||
TakePhotoCamera takePhotoCamera = new TakePhotoCamera();
|
||
takePhotoCamera.operation();
|
||
|
||
System.out.println("\n-----------------分割线-----------------\n");
|
||
|
||
BeautyCamera beautyCamera = new BeautyCamera(takePhotoCamera);
|
||
beautyCamera.operation();
|
||
|
||
System.out.println("\n-----------------分割线-----------------\n");
|
||
|
||
FilterCamera filterCamera = new FilterCamera(beautyCamera);
|
||
filterCamera.operation();
|
||
|
||
System.out.println("\n-----------------分割线-----------------\n");
|
||
|
||
TimerCamera timerCamera = new TimerCamera();
|
||
timerCamera.setTime(2);
|
||
timerCamera.operation();
|
||
filterCamera = new FilterCamera(beautyCamera);
|
||
filterCamera.operation();
|
||
}
|
||
|
||
// 相机功能
|
||
interface Camera {
|
||
|
||
/**
|
||
* 相机操作
|
||
*/
|
||
void operation();
|
||
}
|
||
|
||
// 相机装饰者角色
|
||
static abstract class CameraDecorator implements Camera {
|
||
Camera camera;
|
||
|
||
public CameraDecorator(Camera camera) {
|
||
this.camera = camera;
|
||
}
|
||
}
|
||
|
||
// 相机拍照
|
||
static class TakePhotoCamera implements Camera {
|
||
|
||
/**
|
||
* 相机操作
|
||
*/
|
||
@Override
|
||
public void operation() {
|
||
System.out.println("相机拍照。。。");
|
||
}
|
||
}
|
||
|
||
// 相机功能
|
||
static class BeautyCamera extends CameraDecorator {
|
||
|
||
public BeautyCamera(Camera camera) {
|
||
super(camera);
|
||
}
|
||
|
||
/**
|
||
* 相机操作
|
||
*/
|
||
@Override
|
||
public void operation() {
|
||
camera.operation();
|
||
System.out.println("美颜功能。。。");
|
||
}
|
||
}
|
||
|
||
// 滤镜效果
|
||
static class FilterCamera extends CameraDecorator {
|
||
|
||
public FilterCamera(Camera camera) {
|
||
super(camera);
|
||
}
|
||
|
||
/**
|
||
* 相机操作
|
||
*/
|
||
@Override
|
||
public void operation() {
|
||
camera.operation();
|
||
System.out.println("滤镜效果。。。");
|
||
}
|
||
}
|
||
|
||
// 实现相机延迟功能
|
||
@Setter
|
||
static class TimerCamera implements Camera {
|
||
|
||
// 延迟时间
|
||
private Integer time = 0;
|
||
|
||
/**
|
||
* 相机操作
|
||
*/
|
||
@Override
|
||
public void operation() {
|
||
System.out.println("开始拍照,延迟时间:" + time + "s");
|
||
try {
|
||
Thread.sleep(time * 1000);
|
||
} catch (InterruptedException e) {
|
||
throw new RuntimeException(e);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 运行结果:
|
||
|
||
```java
|
||
相机拍照。。。
|
||
|
||
-----------------分割线-----------------
|
||
|
||
相机拍照。。。
|
||
美颜功能。。。
|
||
|
||
-----------------分割线-----------------
|
||
|
||
相机拍照。。。
|
||
美颜功能。。。
|
||
滤镜效果。。。
|
||
|
||
-----------------分割线-----------------
|
||
|
||
开始拍照,延迟时间:2s
|
||
相机拍照。。。
|
||
美颜功能。。。
|
||
滤镜效果。。。
|
||
```
|
||
|
||
---
|
||
|
||
## 外观模式---结构型
|
||
|
||
有点类似网址导航的思想,比如有很多零散的东西(网址)但是每次我们想用的时候需要寻找这些网址,如果有个网址大全讲这些网址封装我们寻找会方便很多。
|
||
|
||
再或者,我们每天看天气,需要打开手机点开天气应用、熄屏;如果我们将这些东西封装成单独的指令会简化我们平时的行为,比如写个脚本执行上面的事情。
|
||
|
||
主要角色:门面角色(Facade)、子系统角色(Sub System)、客户角色(Client)。
|
||
|
||
![image-20250203154216552](./images/设计模式-v2/image-20250203154216552.png)
|
||
|
||
### 简单实现
|
||
|
||
#### 示例代码
|
||
|
||
```java
|
||
public class Facade {
|
||
public static void main(String[] args) {
|
||
DeviceFacade deviceFacade = new DeviceFacade();
|
||
// 查看
|
||
deviceFacade.on();
|
||
|
||
// 看完关闭
|
||
deviceFacade.off();
|
||
}
|
||
|
||
// 子系统-手机
|
||
static class SubSystemIPhone {
|
||
public void on() {
|
||
System.out.println("打开手机。。。");
|
||
}
|
||
|
||
public void off() {
|
||
System.out.println("关闭手机。。。");
|
||
}
|
||
}
|
||
|
||
// 子系统-天气
|
||
static class SubSystemWeather {
|
||
public void on() {
|
||
System.out.println("打开天气。。。");
|
||
}
|
||
|
||
public void off() {
|
||
System.out.println("关闭天气。。。");
|
||
}
|
||
}
|
||
|
||
// 门面
|
||
static class DeviceFacade {
|
||
// 也可以作为参数传递,如果没有别的实现类,直接在内部初始化会使使用者更简单
|
||
SubSystemIPhone subSystemIPhone = new SubSystemIPhone();
|
||
SubSystemWeather subSystemWeather = new SubSystemWeather();
|
||
|
||
public void on() {
|
||
subSystemIPhone.on();
|
||
subSystemWeather.on();
|
||
}
|
||
|
||
public void off() {
|
||
subSystemWeather.off();
|
||
subSystemIPhone.off();
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 运行结果:
|
||
|
||
```java
|
||
打开手机。。。
|
||
打开天气。。。
|
||
关闭天气。。。
|
||
关闭手机。。。
|
||
```
|
||
|
||
---
|
||
|
||
## 适配器模式---结构型
|
||
|
||
需要角色:抽象适配者角色(Abstract Adapter)、适配者角色(Adapter)、目标角色(Target)
|
||
|
||
在生活中,有时需要将380V三相电转成220V,这时候需要变压器,当然也有三相电转两相电接法,我们可以使用代码模拟这个操作 。
|
||
|
||
![](./images/设计模式-v2/v2-8efc399313ae3746932c63069aa103b0_1440w-1738507407103-4.avif)
|
||
|
||
### 类适配器
|
||
|
||
![image-20250202222740030](./images/设计模式-v2/image-20250202222740030.png)
|
||
|
||
#### 示例代码
|
||
|
||
```java
|
||
public class Adapter1 {
|
||
public static void main(String[] args) {
|
||
PowerAdapter powerAdapter = new PowerAdapter();
|
||
Integer integer = powerAdapter.output220V();
|
||
|
||
System.out.println("----------------");
|
||
|
||
PowerAdapter powerAdapter1 = new PowerAdapter();
|
||
powerAdapter1.output220V();
|
||
Integer i = powerAdapter1.output380V();
|
||
}
|
||
|
||
// 电压输出
|
||
interface PowerTarget {
|
||
/**
|
||
* 输出电压220V
|
||
*
|
||
* @return 输出电压
|
||
*/
|
||
Integer output220V();
|
||
}
|
||
|
||
static class PowerAdapter extends Power implements PowerTarget {
|
||
|
||
/**
|
||
* 输出电压220V
|
||
*
|
||
* @return 输出电压
|
||
*/
|
||
@Override
|
||
public Integer output220V() {
|
||
Integer output = super.getOutput();
|
||
System.out.println("变压器交流" + output + "v转220v三相电变两项电。。。");
|
||
|
||
double adapter = new Random().nextDouble(1.64, 1.72);
|
||
Integer newOutput = (int) (output / adapter);
|
||
System.out.println("变压器转换完成:电压输出为:" + newOutput);
|
||
|
||
return newOutput;
|
||
}
|
||
}
|
||
|
||
@Data
|
||
static class Power {
|
||
private Integer output = 380;
|
||
|
||
public Integer output380V() {
|
||
System.out.println("输出电压:" + output);
|
||
return output;
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 运行结果:
|
||
|
||
```java
|
||
变压器交流380v转220v三相电变两项电。。。
|
||
变压器转换完成:电压输出为:224
|
||
----------------
|
||
变压器交流380v转220v三相电变两项电。。。
|
||
变压器转换完成:电压输出为:224
|
||
输出电压:380
|
||
```
|
||
|
||
### 对象适配器
|
||
|
||
![image-20250202223220831](./images/设计模式-v2/image-20250202223220831.png)
|
||
|
||
#### 示例代码
|
||
|
||
```java
|
||
public class Adapter2 {
|
||
public static void main(String[] args) {
|
||
Power power = new Power();
|
||
PowerAdapter powerAdapter = new PowerAdapter(power);
|
||
Integer integer = powerAdapter.output220V();
|
||
}
|
||
|
||
// 电压输出
|
||
interface PowerTarget {
|
||
/**
|
||
* 输出电压220V
|
||
*
|
||
* @return 输出电压
|
||
*/
|
||
Integer output220V();
|
||
}
|
||
|
||
@Setter
|
||
@Getter
|
||
static class PowerAdapter implements PowerTarget {
|
||
private final Power power;
|
||
|
||
public PowerAdapter(Power power) {
|
||
this.power = power;
|
||
}
|
||
|
||
/**
|
||
* 输出电压220V
|
||
*
|
||
* @return 输出电压
|
||
*/
|
||
@Override
|
||
public Integer output220V() {
|
||
Integer output = power.getOutput();
|
||
System.out.println("变压器交流" + output + "v转220v三相电变两项电。。。");
|
||
|
||
double adapter = new Random().nextDouble(1.64, 1.72);
|
||
Integer newOutput = (int) (output / adapter);
|
||
System.out.println("变压器转换完成:电压输出为:" + newOutput);
|
||
|
||
return newOutput;
|
||
}
|
||
|
||
}
|
||
|
||
@Data
|
||
static class Power {
|
||
private Integer output = 380;
|
||
|
||
public Integer output380V() {
|
||
System.out.println("输出电压:" + output);
|
||
return output;
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 运行结果 :
|
||
|
||
```java
|
||
变压器交流380v转220v三相电变两项电。。。
|
||
变压器转换完成:电压输出为:224
|
||
```
|
||
|
||
### 缺省适配器
|
||
|
||
![image-20250202224211540](./images/设计模式-v2/image-20250202224211540.png)
|
||
|
||
#### 示例代码
|
||
|
||
```java
|
||
public class Adapter3 {
|
||
public static void main(String[] args) {
|
||
Power power = new Power();
|
||
PowerAdapter powerAdapter = new Power220VAdapter(power);
|
||
Integer integer = powerAdapter.output220V();
|
||
}
|
||
|
||
// 电压输出
|
||
interface PowerTarget {
|
||
/**
|
||
* 输出电压24V
|
||
*
|
||
* @return 输出电压
|
||
*/
|
||
Integer output24V();
|
||
|
||
/**
|
||
* 输出电压110V
|
||
*
|
||
* @return 输出电压
|
||
*/
|
||
Integer output110V();
|
||
|
||
/**
|
||
* 输出电压220V
|
||
*
|
||
* @return 输出电压
|
||
*/
|
||
Integer output220V();
|
||
}
|
||
|
||
@Data
|
||
static abstract class PowerAdapter implements PowerTarget {
|
||
protected Power power;
|
||
|
||
public PowerAdapter(Power power) {
|
||
this.power = power;
|
||
}
|
||
|
||
/**
|
||
* 输出电压24V
|
||
*
|
||
* @return 输出电压
|
||
*/
|
||
@Override
|
||
public Integer output24V() {
|
||
return 0;
|
||
}
|
||
|
||
/**
|
||
* 输出电压110V
|
||
*
|
||
* @return 输出电压
|
||
*/
|
||
@Override
|
||
public Integer output110V() {
|
||
return 0;
|
||
}
|
||
|
||
/**
|
||
* 输出电压220V
|
||
*
|
||
* @return 输出电压
|
||
*/
|
||
@Override
|
||
public Integer output220V() {
|
||
return 0;
|
||
}
|
||
}
|
||
|
||
// 缺省适配器转换器
|
||
static class Power220VAdapter extends PowerAdapter {
|
||
public Power220VAdapter(Power power) {
|
||
super(power);
|
||
}
|
||
|
||
/**
|
||
* 输出电压220V
|
||
*
|
||
* @return 输出电压
|
||
*/
|
||
@Override
|
||
public Integer output220V() {
|
||
Integer output = power.getOutput();
|
||
System.out.println("变压器开始转换:" + output + "v转220v三相电变两项电。。。");
|
||
|
||
double adapter = new Random().nextDouble(1.64, 1.72);
|
||
Integer newOutput = (int) (output / adapter);
|
||
System.out.println("变压器转换完成:电压输出为:" + newOutput);
|
||
|
||
return newOutput;
|
||
}
|
||
}
|
||
|
||
@Data
|
||
static class Power {
|
||
private Integer output = 380;
|
||
|
||
public Integer output380V() {
|
||
System.out.println("输出电压:" + output);
|
||
return output;
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 运行结果:
|
||
|
||
```java
|
||
变压器开始转换:380v转220v三相电变两项电。。。
|
||
变压器转换完成:电压输出为:224
|
||
```
|
||
|
||
---
|
||
|
||
## 组合模式---结构型
|
||
|
||
组合模式(Composite Pattern)是一种结构型设计模式,用于将对象组合成树形结构以表示“部分-整体”层次结构。组合模式让客户端以统一的方式对待单个对象和对象组合。
|
||
|
||
![image-20250203210907388](./images/设计模式-v2/image-20250203210907388.png)
|
||
|
||
1. **Component(抽象组件)**:
|
||
- 定义了组合对象和叶子对象的共同接口。
|
||
- 在组合模式中,所有的“叶子”和“容器”类都实现此接口,因此客户端可以一致地对待这些对象。
|
||
- 例如,可以定义一个 `Operation` 方法,使得所有的组件(无论是叶子对象还是组合对象)都能执行该操作。
|
||
2. **Leaf(叶子节点)**:
|
||
- 叶子对象表示树的最末端元素,不再有子对象。
|
||
- 叶子对象继承自 `Component` 类,具体实现功能。
|
||
- 叶子对象不再包含子节点。
|
||
3. **Composite(组合节点)**:
|
||
- 组合对象也实现了 `Component` 接口,且包含多个子组件(即可以包含其他 `Leaf` 或 `Composite` 对象)。
|
||
- 组合节点负责将所有的叶子节点和子组合节点组织起来,实现“部分-整体”的结构。
|
||
|
||
### 简单示例
|
||
|
||
#### 示例代码
|
||
|
||
```java
|
||
public class Composite {
|
||
public static void main(String[] args) {
|
||
ConcreteCompany company = new ConcreteCompany("总公司");
|
||
|
||
// 总公司的分公司
|
||
ConcreteCompany subCompany1 = new ConcreteCompany("上海分公司");
|
||
subCompany1.add(new HRDepartment("上海华东分公司"));
|
||
subCompany1.add(new FinanceDepartment("上海华东分公司"));
|
||
company.add(subCompany1);
|
||
|
||
// 总公司的分公司
|
||
ConcreteCompany subCompany2 = new ConcreteCompany("北京分公司");
|
||
subCompany2.add(new HRDepartment("北京华东分公司"));
|
||
subCompany2.add(new FinanceDepartment("北京华东分公司"));
|
||
company.add(subCompany2);
|
||
|
||
// 上海的南京分公司
|
||
ConcreteCompany subCompany3 = new ConcreteCompany("南京分公司");
|
||
subCompany3.add(new HRDepartment("南京华东分公司"));
|
||
subCompany3.add(new FinanceDepartment("南京华东分公司"));
|
||
subCompany1.add(subCompany3);
|
||
|
||
System.out.println("---------------------显示组织图---------------------");
|
||
company.display(1);
|
||
|
||
System.out.println("---------------------显示职责---------------------");
|
||
company.duty();
|
||
}
|
||
|
||
// Component 抽象子组件
|
||
abstract static class Company {
|
||
protected String name;
|
||
|
||
public Company(String name) {
|
||
this.name = name;
|
||
}
|
||
|
||
/**
|
||
* 添加节点
|
||
*
|
||
* @param company 子组件
|
||
*/
|
||
public abstract void add(Company company);
|
||
|
||
/**
|
||
* 删除节点
|
||
*
|
||
* @param company 子组件
|
||
*/
|
||
public abstract void remove(Company company);
|
||
|
||
/**
|
||
* 显示
|
||
*
|
||
* @param depth 深度
|
||
*/
|
||
public abstract void display(int depth);
|
||
|
||
/**
|
||
* 职责
|
||
*/
|
||
public abstract void duty();
|
||
}
|
||
|
||
// 容器对象
|
||
static class ConcreteCompany extends Company {
|
||
|
||
private final List<Company> companyList = new ArrayList<>();
|
||
|
||
public ConcreteCompany(String name) {
|
||
super(name);
|
||
}
|
||
|
||
/**
|
||
* 添加节点
|
||
*
|
||
* @param company 子组件
|
||
*/
|
||
@Override
|
||
public void add(Company company) {
|
||
companyList.add(company);
|
||
}
|
||
|
||
/**
|
||
* 删除节点
|
||
*
|
||
* @param company 子组件
|
||
*/
|
||
@Override
|
||
public void remove(Company company) {
|
||
companyList.remove(company);
|
||
}
|
||
|
||
/**
|
||
* 显示
|
||
*
|
||
* @param depth 深度
|
||
*/
|
||
@Override
|
||
public void display(int depth) {
|
||
for (int i = 0; i < depth; i++) System.out.print("-");
|
||
|
||
System.out.println(name);
|
||
|
||
for (Company company : companyList) {
|
||
company.display(depth + 1);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 职责
|
||
*/
|
||
@Override
|
||
public void duty() {
|
||
for (Company company : companyList) {
|
||
company.duty();
|
||
}
|
||
}
|
||
}
|
||
|
||
// 人事部门
|
||
static class HRDepartment extends Company {
|
||
public HRDepartment(String name) {
|
||
super(name);
|
||
}
|
||
|
||
/**
|
||
* 添加节点
|
||
*
|
||
* @param company 子组件
|
||
*/
|
||
@Override
|
||
public void add(Company company) {
|
||
}
|
||
|
||
/**
|
||
* 删除节点
|
||
*
|
||
* @param company 子组件
|
||
*/
|
||
@Override
|
||
public void remove(Company company) {
|
||
}
|
||
|
||
/**
|
||
* 显示
|
||
*
|
||
* @param depth 深度
|
||
*/
|
||
@Override
|
||
public void display(int depth) {
|
||
for (int i = 0; i < depth; i++) System.out.print("-");
|
||
System.out.println(name);
|
||
}
|
||
|
||
/**
|
||
* 职责
|
||
*/
|
||
@Override
|
||
public void duty() {
|
||
System.out.println(name + ":员工招聘培训管理");
|
||
}
|
||
}
|
||
|
||
// 财务部
|
||
static class FinanceDepartment extends Company {
|
||
public FinanceDepartment(String name) {
|
||
super(name);
|
||
}
|
||
|
||
/**
|
||
* 添加节点
|
||
*
|
||
* @param company 子组件
|
||
*/
|
||
@Override
|
||
public void add(Company company) {
|
||
}
|
||
|
||
/**
|
||
* 删除节点
|
||
*
|
||
* @param company 子组件
|
||
*/
|
||
@Override
|
||
public void remove(Company company) {
|
||
}
|
||
|
||
/**
|
||
* 显示
|
||
*
|
||
* @param depth 深度
|
||
*/
|
||
@Override
|
||
public void display(int depth) {
|
||
for (int i = 0; i < depth; i++) System.out.print("-");
|
||
System.out.println(name);
|
||
}
|
||
|
||
/**
|
||
* 职责
|
||
*/
|
||
@Override
|
||
public void duty() {
|
||
System.out.println(name + ":公司财务收支管理");
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 运行结果:
|
||
|
||
```java
|
||
---------------------显示组织图---------------------
|
||
-总公司
|
||
--上海分公司
|
||
---上海华东分公司
|
||
---上海华东分公司
|
||
---南京分公司
|
||
----南京华东分公司
|
||
----南京华东分公司
|
||
--北京分公司
|
||
---北京华东分公司
|
||
---北京华东分公司
|
||
---------------------显示职责---------------------
|
||
上海华东分公司:员工招聘培训管理
|
||
上海华东分公司:公司财务收支管理
|
||
南京华东分公司:员工招聘培训管理
|
||
南京华东分公司:公司财务收支管理
|
||
北京华东分公司:员工招聘培训管理
|
||
北京华东分公司:公司财务收支管理
|
||
```
|
||
|
||
---
|
||
|
||
## 享元模式---结构型
|
||
|
||
享元模式(Flyweight Pattern)是一种结构型设计模式,它的主要目的是通过共享对象来减少内存使用和提高性能。在享元模式中,系统中可能会有很多重复的对象,而享元模式通过将这些对象分为“共享部分”和“非共享部分”,只在共享部分创建单一实例,来优化内存使用。
|
||
|
||
![image-20250204191157193](./images/设计模式-v2/image-20250204191157193.png)
|
||
|
||
**需要角色**
|
||
|
||
**Flyweight(享元类)**:负责实现共享的对象部分,通常是不可变的状态。它是享元模式的核心,通过共享相同的状态,减少内存消耗。
|
||
|
||
**ConcreteFlyweight(具体享元类)**:是Flyweight的具体实现,负责实现具体的共享对象。具体享元类一般会包含一个外部状态,它并不存储该状态,而是通过外部传入的方式进行变化。
|
||
|
||
**FlyweightFactory(享元工厂类)**:是一个工厂,负责管理共享的享元对象。在客户端请求享元对象时,它会从池中查找是否已有实例,如果有则返回,若没有则创建新的享元对象并将其返回。
|
||
|
||
**Client(客户端)**:负责根据外部状态请求享元对象。客户端会传递外部状态(不共享的部分)给享元对象,而享元对象则只关注内部共享部分。
|
||
|
||
### 简单示例
|
||
|
||
#### 示例代码
|
||
|
||
```java
|
||
public class FlyWeight {
|
||
public static void main(String[] args) {
|
||
// 第一次获取对象会进行资源创建
|
||
GirlFriend girlFriend1 = GirlFriendFactory.getGirlFriend("第一个女朋友");
|
||
GirlFriend girlFriend2 = GirlFriendFactory.getGirlFriend("第二个女朋友");
|
||
|
||
// 第二次获取对象直接从容器中获取
|
||
GirlFriend girlFriend11 = GirlFriendFactory.getGirlFriend("第一个女朋友");
|
||
GirlFriend girlFriend22 = GirlFriendFactory.getGirlFriend("第二个女朋友");
|
||
|
||
System.out.println(girlFriend1 == girlFriend11);// true
|
||
System.out.println(girlFriend2 == girlFriend22);// true
|
||
}
|
||
|
||
@Data
|
||
static class GirlFriend {
|
||
private String name;
|
||
private Integer age;
|
||
}
|
||
|
||
static class GirlFriendFactory {
|
||
private static final Map<String, GirlFriend> map = new HashMap<>();
|
||
|
||
public static GirlFriend getGirlFriend(String name) {
|
||
GirlFriend girlFriend = map.get(name);
|
||
if (girlFriend == null) {
|
||
girlFriend = new GirlFriend();
|
||
girlFriend.name = name;
|
||
map.put(name, girlFriend);
|
||
}
|
||
return girlFriend;
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 运行结果:
|
||
|
||
```java
|
||
true
|
||
true
|
||
```
|
||
|
||
## 代理模式---结构型
|
||
|
||
### 静态代理-1
|
||
|
||
![image-20250204185312828](./images/设计模式-v2/image-20250204185312828.png)
|
||
|
||
如果是静态代理,做Java开发几乎都在用,就是抽象接口和实现,比如:`UserService`之后`UserServiceImpl`实现`UserService`,就是这个,之后使用`UserService`进行调用实现中的方法。
|
||
|
||
### 静态代理-2
|
||
|
||
![image-20250204185852710](./images/设计模式-v2/image-20250204185852710.png)
|
||
|
||
#### 示例代码
|
||
|
||
```java
|
||
public class Proxy {
|
||
public static void main(String[] args) {
|
||
UserServiceProxy proxy = new UserServiceProxy(new UserServiceImpl());
|
||
proxy.saveUser();
|
||
proxy.findUser(1L);
|
||
}
|
||
|
||
interface UserService {
|
||
|
||
/**
|
||
* 保存用户
|
||
*/
|
||
void saveUser();
|
||
|
||
/**
|
||
* 查找用户
|
||
*/
|
||
Object findUser(Long id);
|
||
}
|
||
|
||
static class UserServiceImpl implements UserService {
|
||
|
||
/**
|
||
* 保存用户
|
||
*/
|
||
@Override
|
||
public void saveUser() {
|
||
System.out.println("保存用户");
|
||
}
|
||
|
||
/**
|
||
* 查找用户
|
||
*
|
||
* @param id id
|
||
*/
|
||
@Override
|
||
public Object findUser(Long id) {
|
||
System.out.println("查找用户");
|
||
return "User{name:'代理'}";
|
||
}
|
||
}
|
||
|
||
static class UserServiceProxy implements UserService {
|
||
|
||
private final UserService userService;
|
||
|
||
public UserServiceProxy(UserService userService) {
|
||
this.userService = userService;
|
||
}
|
||
|
||
/**
|
||
* 保存用户
|
||
*/
|
||
@Override
|
||
public void saveUser() {
|
||
userService.saveUser();
|
||
}
|
||
|
||
/**
|
||
* 查找用户
|
||
*
|
||
* @param id id
|
||
*/
|
||
@Override
|
||
public Object findUser(Long id) {
|
||
return userService.findUser(id);
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 运行结果:
|
||
|
||
```java
|
||
保存用户
|
||
查找用户
|
||
```
|
||
|
||
---
|
||
|
||
## 桥接模式---结构型
|
||
|
||
桥接模式通过“桥接”抽象和实现,使得两者可以独立地变化。它通常应用于那些有多个维度可扩展的系统中,这样可以避免类爆炸,减少子类的数量,提升代码的可维护性。
|
||
|
||
![image-20250205223403477](./images/设计模式-v2/image-20250205223403477.png)
|
||
|
||
**需要角色**
|
||
|
||
**Abstraction(抽象化角色)**:
|
||
|
||
- 定义了抽象部分的接口,并且保持一个指向实现部分的引用。
|
||
|
||
**RefinedAbstraction(扩充抽象化角色)**:
|
||
|
||
- 继承自 Abstraction,通常会扩展其接口。
|
||
|
||
**Implementor(实现者角色)**:
|
||
|
||
- 定义了实现类的接口,这个接口不会太复杂,可以和抽象角色分离。
|
||
|
||
**ConcreteImplementor(具体实现者角色)**:
|
||
|
||
- 实现了 Implementor 接口,定义了具体的实现方式。
|
||
|
||
### 简单示例
|
||
|
||
#### 示例代码
|
||
|
||
```java
|
||
public class Bridge {
|
||
public static void main(String[] args) {
|
||
// 使用不同的绘制方式
|
||
Shape circle1 = new Circle(5, 10, 2, new DrawingAPI1()); // 使用屏幕绘制
|
||
Shape circle2 = new Circle(10, 20, 3, new DrawingAPI2()); // 使用打印机绘制
|
||
|
||
circle1.draw();
|
||
circle2.draw();
|
||
|
||
// 调整圆形大小
|
||
circle1.resize(1.5);
|
||
circle2.resize(0.5);
|
||
|
||
circle1.draw();
|
||
circle2.draw();
|
||
}
|
||
|
||
// Implementor: 定义绘制图形的接口
|
||
interface DrawingAPI {
|
||
void drawCircle(double x, double y, double radius);
|
||
}
|
||
|
||
// ConcreteImplementor: 屏幕绘制实现
|
||
static class DrawingAPI1 implements DrawingAPI {
|
||
@Override
|
||
public void drawCircle(double x, double y, double radius) {
|
||
System.out.println("Drawing Circle on Screen: (" + x + ", " + y + ") with radius " + radius);
|
||
}
|
||
}
|
||
|
||
// ConcreteImplementor: 打印机绘制实现
|
||
static class DrawingAPI2 implements DrawingAPI {
|
||
@Override
|
||
public void drawCircle(double x, double y, double radius) {
|
||
System.out.println("Drawing Circle on Printer: (" + x + ", " + y + ") with radius " + radius);
|
||
}
|
||
}
|
||
|
||
// Abstraction: 定义图形接口
|
||
static abstract class Shape {
|
||
protected DrawingAPI drawingAPI;
|
||
|
||
protected Shape(DrawingAPI drawingAPI) {
|
||
this.drawingAPI = drawingAPI;
|
||
}
|
||
|
||
public abstract void draw();
|
||
|
||
public abstract void resize(double factor);
|
||
}
|
||
|
||
// RefinedAbstraction: 圆形
|
||
static class Circle extends Shape {
|
||
private final double x;
|
||
private final double y;
|
||
private double 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;
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 运行结果:
|
||
|
||
```java
|
||
Drawing Circle on Screen: (5.0, 10.0) with radius 2.0
|
||
Drawing Circle on Printer: (10.0, 20.0) with radius 3.0
|
||
Drawing Circle on Screen: (5.0, 10.0) with radius 3.0
|
||
Drawing Circle on Printer: (10.0, 20.0) with radius 1.5
|
||
```
|
||
|
||
---
|
||
|
||
## 策略模式---行为型
|
||
|
||
### 常见应用场景
|
||
|
||
策略模式广泛应用于支付、计算、文件压缩、登录等场景,尤其是在游戏中,如王者荣耀和PUBG的角色处理。值得注意的是,在实际开发中,一种业务场景可能会同时使用多种设计模式,因此,下面的介绍仅为简化并专注于策略模式的核心概念。
|
||
|
||
### 策略模式基础介绍
|
||
|
||
策略模式涉及三个主要角色:
|
||
|
||
1. **抽象策略(Strategy)**
|
||
2. **具体策略(Concrete Strategy)**
|
||
3. **上下文(Context)**
|
||
|
||
其中,`Context` 的概念较为抽象,通常用来持有策略并在运行时动态地切换策略。
|
||
|
||
![策略模式结构图](./images/设计模式-v2/image-20250201164040235.png)
|
||
|
||
#### 代码实现
|
||
|
||
策略模式的实现并不复杂,主要是定义三个角色:抽象策略、具体策略和上下文。为了更清晰地展示,我定义了两个具体策略,每个策略执行不同的操作。然后将策略放入上下文中,最终通过上下文来执行具体策略的方法。
|
||
|
||
```java
|
||
public class BaseStrategy {
|
||
|
||
public static void main(String[] args) {
|
||
// 创建具体策略
|
||
ConcreteStrategy1 concreteStrategy1 = new ConcreteStrategy1();
|
||
ConcreteStrategy2 concreteStrategy2 = new ConcreteStrategy2();
|
||
|
||
// 通过上下文执行策略
|
||
new Context(concreteStrategy1).doIt();
|
||
new Context(concreteStrategy2).doIt();
|
||
}
|
||
|
||
// 抽象策略接口
|
||
public interface Strategy {
|
||
/**
|
||
* 执行策略方法
|
||
*/
|
||
void method();
|
||
}
|
||
|
||
// 具体策略实现1
|
||
public static class ConcreteStrategy1 implements Strategy {
|
||
@Override
|
||
public void method() {
|
||
System.out.println("执行具体策略1...");
|
||
}
|
||
}
|
||
|
||
// 具体策略实现2
|
||
public static class ConcreteStrategy2 implements Strategy {
|
||
@Override
|
||
public void method() {
|
||
System.out.println("执行具体策略2...");
|
||
}
|
||
}
|
||
|
||
// 上下文类,持有策略并执行
|
||
public static class Context {
|
||
private final Strategy strategy;
|
||
|
||
public Context(Strategy strategy) {
|
||
this.strategy = strategy;
|
||
}
|
||
|
||
/**
|
||
* 执行策略的方法
|
||
*/
|
||
public void doIt() {
|
||
strategy.method();
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 执行结果:
|
||
|
||
```java
|
||
执行具体策略1...
|
||
执行具体策略2...
|
||
```
|
||
|
||
### 示例-游戏角色
|
||
|
||
需要制作的游戏角色业务需求,基础角色是其他角色的抽象,包括国王、王后、骑士、士兵等,武器是一个接口所有武器都实现这个接口,切换武器(武器有主武器和副武器)可以调用`setPrimaryWeapon`和`setSubWeapon`。
|
||
|
||
![image-20250201173433406](./images/设计模式-v2/image-20250201173433406.png)
|
||
|
||
#### 代码实现
|
||
|
||
```java
|
||
public class GameCharacter {
|
||
public static void main(String[] args) {
|
||
Character soldier = new Soldier();
|
||
soldier.fight();
|
||
|
||
Character king = new King();
|
||
king.setPrimaryWeapon(new AxeWeapon());
|
||
king.fight();
|
||
}
|
||
|
||
// 武器接口
|
||
interface Weapon {
|
||
String function();
|
||
}
|
||
|
||
// 各种武器实现
|
||
public static class SwordWeapon implements Weapon {
|
||
@Override
|
||
public String function() {
|
||
return "⚔️ ⚔️ ⚔️";
|
||
}
|
||
}
|
||
|
||
public static class AxeWeapon implements Weapon {
|
||
@Override
|
||
public String function() {
|
||
return "🪓 🪓 🪓";
|
||
}
|
||
}
|
||
|
||
public static class KnifeWeapon implements Weapon {
|
||
@Override
|
||
public String function() {
|
||
return "🔪 🔪 🔪";
|
||
}
|
||
}
|
||
|
||
// 抽象角色类
|
||
public abstract static class Character {
|
||
String name;
|
||
@Setter
|
||
private Weapon primaryWeapon;
|
||
@Setter
|
||
private Weapon subWeapon;
|
||
|
||
public Character(String name) {
|
||
this.name = name;
|
||
// 默认武器配置
|
||
this.primaryWeapon = new SwordWeapon();
|
||
this.subWeapon = new KnifeWeapon();
|
||
}
|
||
|
||
void fight() {
|
||
if (primaryWeapon != null && subWeapon != null) {
|
||
String primary = primaryWeapon.function();
|
||
String sub = subWeapon.function();
|
||
System.out.println(name + ":" + primary + "和" + sub);
|
||
} else {
|
||
System.out.println(name + "没有武器!");
|
||
}
|
||
}
|
||
}
|
||
|
||
// 国王角色
|
||
public static class King extends Character {
|
||
public King() {
|
||
super("King");
|
||
setPrimaryWeapon(new SwordWeapon());
|
||
setSubWeapon(new KnifeWeapon());
|
||
}
|
||
}
|
||
|
||
// 士兵角色
|
||
public static class Soldier extends Character {
|
||
public Soldier() {
|
||
super("Soldier");
|
||
setPrimaryWeapon(new AxeWeapon());
|
||
setSubWeapon(new SwordWeapon());
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 运行结果:
|
||
|
||
```java
|
||
Soldier:🪓 🪓 🪓和⚔️ ⚔️ ⚔️
|
||
King:🪓 🪓 🪓和🔪 🔪 🔪
|
||
```
|
||
|
||
---
|
||
|
||
## 观察者模式---行为型
|
||
|
||
观察者有四个角色,观察者(Observe)和具体观察者(Concrete Observe)、主题(Subject)和具体主题(Concrete Subject),具体观察者和具体主题可以多个。
|
||
|
||
![image-20250201175728138](./images/设计模式-v2/image-20250201175728138.png)
|
||
|
||
### 简单示例
|
||
|
||
其中主题中有3个方法,添加(或者理解成注册都可以)、移出、通知,差不多都是这三个方法,其中添加可以理解成注册加入总之是往数组中添加观察者。
|
||
|
||
#### 代码实现
|
||
|
||
```java
|
||
public class ObserverDemo {
|
||
public static void main(String[] args) {
|
||
// 定义的主题
|
||
News news = new News();
|
||
|
||
// 观察者
|
||
SisterObserver sisterObserver = new SisterObserver();
|
||
GirlfriendObserver girlfriendObserver = new GirlfriendObserver();
|
||
|
||
// 添加观察者
|
||
news.addObserver(sisterObserver);
|
||
news.notifyObservers("添加了妹妹");
|
||
|
||
System.out.println("\n-----------------分割线-----------------\n");
|
||
|
||
// 添加女朋友
|
||
news.addObserver(girlfriendObserver);
|
||
news.notifyObservers("添加了女朋友");
|
||
|
||
System.out.println("\n-----------------分割线-----------------\n");
|
||
news.removeObserver(girlfriendObserver);
|
||
news.notifyObservers("需要和妹妹说点悄悄话,将女朋友移除了,这时女朋友听不见我们说话。。。");
|
||
}
|
||
|
||
// 观察者接口
|
||
@FunctionalInterface
|
||
interface Observer {
|
||
void update(String message);
|
||
}
|
||
|
||
// 主题接口
|
||
interface Subject {
|
||
void addObserver(Observer observer);
|
||
|
||
void removeObserver(Observer observer);
|
||
|
||
void notifyObservers(String message);
|
||
}
|
||
|
||
// 妹妹观察者
|
||
static class SisterObserver implements Observer {
|
||
@Override
|
||
public void update(String message) {
|
||
System.out.println("SisterObserver 接受到消息:" + message);
|
||
}
|
||
}
|
||
|
||
// 女朋友观察者
|
||
static class GirlfriendObserver implements Observer {
|
||
@Override
|
||
public void update(String message) {
|
||
System.out.println("GirlfriendObserver 接受到消息:" + message);
|
||
}
|
||
}
|
||
|
||
// 主题类
|
||
static class News implements Subject {
|
||
|
||
private final List<Observer> observerList = new ArrayList<>();
|
||
|
||
@Override
|
||
public void addObserver(Observer observer) {
|
||
observerList.add(observer);
|
||
}
|
||
|
||
@Override
|
||
public void removeObserver(Observer observer) {
|
||
observerList.remove(observer);
|
||
}
|
||
|
||
@Override
|
||
public void notifyObservers(String message) {
|
||
for (Observer observer : observerList) {
|
||
observer.update(message);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 运行结果:
|
||
|
||
```java
|
||
SisterObserver 接受到消息:添加了妹妹
|
||
|
||
-----------------分割线-----------------
|
||
|
||
SisterObserver 接受到消息:添加了女朋友
|
||
GirlfriendObserver 接受到消息:添加了女朋友
|
||
|
||
-----------------分割线-----------------
|
||
|
||
SisterObserver 接受到消息:需要和妹妹说点悄悄话,将女朋友移除了,这时女朋友听不见我们说话。。。
|
||
```
|
||
|
||
---
|
||
|
||
## 命令模式---行为型
|
||
|
||
**Command**:定义执行请求的接口(或抽象类)。
|
||
|
||
**ConcreteCommand**:实现命令接口并具体化执行请求的过程,通常还会持有接收者对象。
|
||
|
||
**Receiver**:具体的对象,完成实际的操作任务。
|
||
|
||
**Invoker**:调用命令的对象,触发命令的执行。
|
||
|
||
**Client**:客户端,负责创建并配置命令对象,将命令与接收者绑定,并传递给调用者执行。
|
||
|
||
### 简单示例
|
||
|
||
![image-20250201205350467](./images/设计模式-v2/image-20250201205350467.png)
|
||
|
||
#### 示例代码
|
||
|
||
```java
|
||
public class CommandDemo {
|
||
public static void main(String[] args) {
|
||
Receiver receiver = new Receiver();
|
||
|
||
ConcreteCommand concreteCommand = new ConcreteCommand(receiver);
|
||
|
||
Invoker invoker = new Invoker();
|
||
invoker.setCommand(concreteCommand);
|
||
invoker.invoke();
|
||
}
|
||
|
||
// 命令接口
|
||
interface Command {
|
||
|
||
/**
|
||
* 执行方法
|
||
*/
|
||
void execute();
|
||
}
|
||
|
||
// 接受者
|
||
static class Receiver {
|
||
public void action() {
|
||
System.out.println("接受者 执行。。。");
|
||
}
|
||
}
|
||
|
||
// 具体的执行命令
|
||
static class ConcreteCommand implements Command {
|
||
|
||
private final Receiver receiver;
|
||
|
||
public ConcreteCommand(Receiver receiver) {
|
||
this.receiver = receiver;
|
||
}
|
||
|
||
/**
|
||
* 执行方法
|
||
*/
|
||
@Override
|
||
public void execute() {
|
||
receiver.action();
|
||
}
|
||
}
|
||
|
||
@Setter
|
||
static class Invoker {
|
||
private Command command;
|
||
|
||
public void invoke() {
|
||
command.execute();
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 执行结果:
|
||
|
||
```java
|
||
接受者 执行。。。
|
||
```
|
||
|
||
### 示例-烧烤店
|
||
|
||
![image-20250201205232542](./images/设计模式-v2/image-20250201205232542.png)
|
||
|
||
|
||
|
||
#### 示例代码
|
||
|
||
```java
|
||
public class BakeDemo {
|
||
|
||
// 充当客户端
|
||
public static void main(String[] args) {
|
||
Waiter waiter = new Waiter();
|
||
Barbecue barbecue = new Barbecue();
|
||
|
||
waiter.addCommand(new BakeChickenWing(barbecue));
|
||
waiter.addCommand(new BakeMutton(barbecue));
|
||
|
||
waiter.notifyCommand();
|
||
}
|
||
|
||
// 接受者-厨师
|
||
static class Barbecue {
|
||
|
||
/**
|
||
* 烤串
|
||
*/
|
||
public void bakeMutton() {
|
||
System.out.println("开始烤串。。。");
|
||
}
|
||
|
||
/**
|
||
* 烤鸡翅
|
||
*/
|
||
public void bakeChickenWing() {
|
||
System.out.println("开始烤鸡翅。。。");
|
||
}
|
||
}
|
||
|
||
// 请求者-invoker-服务员
|
||
public static class Waiter {
|
||
private final List<Command> commandList = new ArrayList<>();
|
||
|
||
public void addCommand(Command command) {
|
||
commandList.add(command);
|
||
}
|
||
|
||
/**
|
||
* 通知厨师开始制作
|
||
*/
|
||
public void notifyCommand() {
|
||
for (Command command : commandList) {
|
||
command.execute();
|
||
}
|
||
}
|
||
}
|
||
|
||
public static abstract class Command {
|
||
protected Barbecue barbecue;
|
||
|
||
public Command(Barbecue barbecue) {
|
||
this.barbecue = barbecue;
|
||
}
|
||
|
||
/**
|
||
* 执行方法
|
||
*/
|
||
public abstract void execute();
|
||
}
|
||
|
||
// 命令-烤鸡翅
|
||
public static class BakeChickenWing extends Command {
|
||
|
||
public BakeChickenWing(Barbecue barbecue) {
|
||
super(barbecue);
|
||
}
|
||
|
||
/**
|
||
* 执行方法
|
||
*/
|
||
@Override
|
||
public void execute() {
|
||
barbecue.bakeChickenWing();
|
||
}
|
||
}
|
||
|
||
// 命令-烤串
|
||
public static class BakeMutton extends Command {
|
||
|
||
public BakeMutton(Barbecue barbecue) {
|
||
super(barbecue);
|
||
}
|
||
|
||
/**
|
||
* 执行方法
|
||
*/
|
||
@Override
|
||
public void execute() {
|
||
barbecue.bakeMutton();
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 执行结果:
|
||
|
||
```java
|
||
开始烤鸡翅。。。
|
||
开始烤串。。。
|
||
```
|
||
|
||
---
|
||
|
||
## 状态模式---行为型
|
||
|
||
![image-20250204181749629](./images/设计模式-v2/image-20250204181749629.png)
|
||
|
||
需要角色:状态对象(Context)、状态接口(State)、具体状态实现(Concrete State)
|
||
|
||
### 简单示例
|
||
|
||
#### 示例代码
|
||
|
||
**上下文对象**
|
||
|
||
```java
|
||
@Getter
|
||
public class Lift {
|
||
// 开门状态
|
||
public static LiftState OPEN_STATE = new OpeningLiftState();
|
||
// 关门状态
|
||
public static LiftState CLOSE_STATE = new ClosingLiftState();
|
||
// 运行状态
|
||
public static LiftState RUNNING_STATE = new RunningLiftState();
|
||
// 停止状态
|
||
public static LiftState STOPPING_STATE = new StoppingLiftState();
|
||
|
||
// 当前电梯状态
|
||
private LiftState currentLiftState;
|
||
|
||
public void setCurrentLiftState(LiftState currentState) {
|
||
this.currentLiftState = currentState;
|
||
// 执行开门动作
|
||
this.currentLiftState.lift = this;
|
||
}
|
||
|
||
public void open() {
|
||
currentLiftState.open();
|
||
}
|
||
|
||
public void close() {
|
||
currentLiftState.close();
|
||
}
|
||
|
||
public void run() {
|
||
currentLiftState.run();
|
||
}
|
||
|
||
public void stop() {
|
||
currentLiftState.stop();
|
||
}
|
||
}
|
||
```
|
||
|
||
**抽象状态接口**
|
||
|
||
```java
|
||
@Setter
|
||
abstract class LiftState {
|
||
protected Lift lift;
|
||
|
||
/**
|
||
* 开门动作
|
||
*/
|
||
public abstract void open();
|
||
|
||
/**
|
||
* 关门动作
|
||
*/
|
||
public abstract void close();
|
||
|
||
/**
|
||
* 运行动作
|
||
*/
|
||
public abstract void run();
|
||
|
||
/**
|
||
* 停止动作
|
||
*/
|
||
public abstract void stop();
|
||
}
|
||
```
|
||
|
||
**开门状态---具体状态实现**
|
||
|
||
```java
|
||
public class OpeningLiftState extends LiftState {
|
||
/**
|
||
* 开门动作
|
||
*/
|
||
@Override
|
||
public void open() {
|
||
System.out.println("电梯门慢慢打开。。。");
|
||
}
|
||
|
||
/**
|
||
* 关门动作
|
||
*/
|
||
@Override
|
||
public void close() {
|
||
super.lift.setCurrentLiftState(Lift.CLOSE_STATE);
|
||
super.lift.getCurrentLiftState().close();
|
||
}
|
||
|
||
/**
|
||
* 运行动作
|
||
*/
|
||
@Override
|
||
public void run() {
|
||
|
||
}
|
||
|
||
/**
|
||
* 停止动作
|
||
*/
|
||
@Override
|
||
public void stop() {
|
||
|
||
}
|
||
}
|
||
```
|
||
|
||
**关门状态---具体状态实现**
|
||
|
||
```java
|
||
public class ClosingLiftState extends LiftState {
|
||
/**
|
||
* 开门动作
|
||
*/
|
||
@Override
|
||
public void open() {
|
||
super.lift.setCurrentLiftState(Lift.OPEN_STATE);
|
||
super.lift.getCurrentLiftState().open();
|
||
}
|
||
|
||
/**
|
||
* 关门动作
|
||
*/
|
||
@Override
|
||
public void close() {
|
||
System.out.println("电梯关门。。。");
|
||
}
|
||
|
||
/**
|
||
* 运行动作
|
||
*/
|
||
@Override
|
||
public void run() {
|
||
super.lift.setCurrentLiftState(Lift.RUNNING_STATE);
|
||
super.lift.getCurrentLiftState().run();
|
||
}
|
||
|
||
/**
|
||
* 停止动作
|
||
*/
|
||
@Override
|
||
public void stop() {
|
||
super.lift.setCurrentLiftState(Lift.STOPPING_STATE);
|
||
super.lift.getCurrentLiftState().stop();
|
||
}
|
||
}
|
||
```
|
||
|
||
**运行状态---具体状态实现**
|
||
|
||
```java
|
||
public class RunningLiftState extends LiftState {
|
||
/**
|
||
* 开门动作
|
||
*/
|
||
@Override
|
||
public void open() {
|
||
|
||
}
|
||
|
||
/**
|
||
* 关门动作
|
||
*/
|
||
@Override
|
||
public void close() {
|
||
|
||
}
|
||
|
||
/**
|
||
* 运行动作
|
||
*/
|
||
@Override
|
||
public void run() {
|
||
System.out.println("电梯正在运行。。。");
|
||
}
|
||
|
||
/**
|
||
* 停止动作
|
||
*/
|
||
@Override
|
||
public void stop() {
|
||
super.lift.setCurrentLiftState(Lift.STOPPING_STATE);
|
||
super.lift.getCurrentLiftState().stop();
|
||
}
|
||
}
|
||
```
|
||
|
||
**停止状态---具体状态实现**
|
||
|
||
```java
|
||
public class StoppingLiftState extends LiftState {
|
||
/**
|
||
* 开门动作
|
||
*/
|
||
@Override
|
||
public void open() {
|
||
super.lift.setCurrentLiftState(Lift.OPEN_STATE);
|
||
super.lift.getCurrentLiftState().open();
|
||
}
|
||
|
||
/**
|
||
* 关门动作
|
||
*/
|
||
@Override
|
||
public void close() {
|
||
|
||
}
|
||
|
||
/**
|
||
* 运行动作
|
||
*/
|
||
@Override
|
||
public void run() {
|
||
super.lift.setCurrentLiftState(Lift.RUNNING_STATE);
|
||
super.lift.getCurrentLiftState().run();
|
||
}
|
||
|
||
/**
|
||
* 停止动作
|
||
*/
|
||
@Override
|
||
public void stop() {
|
||
System.out.println("电梯停止。。。");
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 运行结果
|
||
|
||
**当运行时**
|
||
|
||
```java
|
||
public class Client {
|
||
public static void main(String[] args) {
|
||
Lift lift = new Lift();
|
||
lift.setCurrentLiftState(Lift.RUNNING_STATE);
|
||
lift.open();
|
||
lift.run();
|
||
lift.close();
|
||
lift.stop();
|
||
}
|
||
}
|
||
```
|
||
|
||
**运行结果**
|
||
|
||
```java
|
||
电梯正在运行。。。
|
||
电梯停止。。。
|
||
```
|
||
|
||
---
|
||
|
||
## 模板方法模式---行为型
|
||
|
||
将定义好的按步骤执行的内容进行封装,模板方法是比较单间的设计模式,是代码复用的基本技术,在类库中尤其重要,遵循:“抽象类应当拥有尽可能多的可能性,应当拥有尽可能少的数据”。
|
||
|
||
![image-20250203163253869](./images/设计模式-v2/image-20250203163253869.png)
|
||
|
||
需要的角色:抽象类(Abstract Class)、具体类(Concrete Class)。
|
||
|
||
比如做一些比较固定的事情(支付流程处理),但是其中几项内容可能会发生改变。
|
||
|
||
### 简单示例
|
||
|
||
#### 示例代码
|
||
|
||
```java
|
||
public class PaymentProcess {
|
||
public static void main(String[] args) {
|
||
ConcretePaymentProcess concretePaymentProcess = new ConcretePaymentProcess();
|
||
concretePaymentProcess.startProcess();
|
||
}
|
||
|
||
// 抽象模板方法
|
||
static abstract class AbstractPaymentProcess {
|
||
|
||
/**
|
||
* 开始流程
|
||
*/
|
||
public void startProcess() {
|
||
authenticationUser();
|
||
checkBalance();
|
||
executePayment();
|
||
returnPayment();
|
||
}
|
||
|
||
/**
|
||
* 验证用户身份
|
||
*/
|
||
private void authenticationUser() {
|
||
System.out.println("验证用户身份。。。");
|
||
}
|
||
|
||
/**
|
||
* 检查余额
|
||
*/
|
||
public abstract void checkBalance();
|
||
|
||
/**
|
||
* 执行支付
|
||
*/
|
||
private void executePayment() {
|
||
System.out.println("执行支付。。。");
|
||
}
|
||
|
||
/**
|
||
* 返回支付结果
|
||
*/
|
||
public abstract void returnPayment();
|
||
}
|
||
|
||
static class ConcretePaymentProcess extends AbstractPaymentProcess {
|
||
|
||
/**
|
||
* 检查余额
|
||
*/
|
||
@Override
|
||
public void checkBalance() {
|
||
System.out.println("检查完成,我的余额还有:1999亿元");
|
||
}
|
||
|
||
/**
|
||
* 返回支付结果
|
||
*/
|
||
@Override
|
||
public void returnPayment() {
|
||
System.out.println("支付成功,我的余额还有:1994亿元");
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 运行结果:
|
||
|
||
```java
|
||
验证用户身份。。。
|
||
检查完成,我的余额还有:1999亿元
|
||
执行支付。。。
|
||
支付成功,我的余额还有:1994亿元
|
||
```
|
||
|
||
---
|
||
|
||
## 备忘录模式---行为型
|
||
|
||
**定义**:在不破坏封闭的前提下,捕获一个对象内部状态,并在该对象之外保存这个状态,这样以后就将该对象恢复到原先保存的状态。
|
||
|
||
需要角色:Originator(发起人)、Memento(备忘录)、Caretaker(管理者)
|
||
|
||
备忘录可以实现功能:撤销、重做、历史记录、快照。
|
||
|
||
### 简单示例
|
||
|
||
#### 示例代码
|
||
|
||
```java
|
||
public class Memo {
|
||
public static void main(String[] args) {
|
||
// 定义记事本
|
||
NoteEditText noteEditText = new NoteEditText();
|
||
|
||
// 负责管理记事本
|
||
NoteCaretaker noteCaretaker = new NoteCaretaker();
|
||
|
||
// 写入记录
|
||
noteEditText.content = "创建第一条记录。。。";
|
||
noteCaretaker.saveMemo(noteEditText.createMemo());
|
||
|
||
// 再次写入
|
||
noteEditText.content = "第三条记录。。。";
|
||
noteCaretaker.saveMemo(noteEditText.createMemo());
|
||
|
||
// 写错撤销下
|
||
noteEditText.restoreMemo(noteCaretaker.getPrevMemo());
|
||
}
|
||
|
||
// 备忘录角色-备忘录
|
||
@Getter
|
||
static class Memento {
|
||
private final String content;
|
||
|
||
public Memento(String content) {
|
||
this.content = content;
|
||
}
|
||
}
|
||
|
||
// 存储备忘录--管理者
|
||
static class NoteCaretaker {
|
||
private final List<Memento> mementoList = new ArrayList<>();
|
||
|
||
// 存档位置
|
||
private int index = 0;
|
||
|
||
/**
|
||
* 添加内容到备忘录中
|
||
*
|
||
* @param memento 备忘录
|
||
*/
|
||
public void saveMemo(Memento memento) {
|
||
mementoList.add(memento);
|
||
index = mementoList.size() - 1;
|
||
for (Memento memento1 : mementoList) {
|
||
System.out.print(memento1.content + " ");
|
||
}
|
||
System.out.println();
|
||
}
|
||
|
||
/**
|
||
* 获取下一个
|
||
*
|
||
* @return 备忘录
|
||
*/
|
||
public Memento getNextMemo() {
|
||
index = index > (mementoList.size() - 1) ? index : mementoList.size() - 1;
|
||
return mementoList.get(index);
|
||
}
|
||
|
||
/**
|
||
* 获取上一个
|
||
*
|
||
* @return 备忘录
|
||
*/
|
||
public Memento getPrevMemo() {
|
||
index = index > 0 ? (index - 1) : 0;
|
||
return mementoList.get(index);
|
||
}
|
||
}
|
||
|
||
// 负责创建备忘录-发起人
|
||
@Data
|
||
static class NoteEditText {
|
||
private String content;
|
||
|
||
public Memento createMemo() {
|
||
return new Memento(content);
|
||
}
|
||
|
||
public void restoreMemo(Memento memento) {
|
||
this.content = memento.content;
|
||
System.out.println("撤销记录:" + content);
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 运行结果:
|
||
|
||
```java
|
||
创建第一条记录。。。
|
||
创建第一条记录。。。 第三条记录。。。
|
||
撤销记录:创建第一条记录。。。
|
||
```
|
||
|
||
---
|
||
|
||
## 中介者模式---行为型
|
||
|
||
![image-20250204184241160](./images/设计模式-v2/image-20250204184241160.png)
|
||
|
||
需要角色:抽象中介者、具体中介者、抽象同事类、具体同事类
|
||
|
||
### 简单示例
|
||
|
||
#### 代码示例
|
||
|
||
```java
|
||
public class Behavior {
|
||
public static void main(String[] args) {
|
||
// 创建邮局
|
||
PostOfficeImpl postOffice = new PostOfficeImpl();
|
||
|
||
// 创建收信人和接收人
|
||
Me me = new Me(postOffice, "在地球南边");
|
||
You you = new You(postOffice, "在地球北边");
|
||
|
||
// 到邮局建立联系
|
||
postOffice.addPeople(me);
|
||
postOffice.addPeople(you);
|
||
|
||
// 我:
|
||
me.sendLetter("我的消息", "You");
|
||
System.out.println("---------------分隔线---------------");
|
||
|
||
// 你:
|
||
you.sendLetter("你的回信", "You");
|
||
System.out.println("---------------分隔线---------------");
|
||
|
||
// 我:
|
||
me.sendLetter("哈哈哈哈哈哈哈哈哈", "You");
|
||
}
|
||
|
||
// 抽象中介者
|
||
interface PostOffice {
|
||
|
||
/**
|
||
* 送信
|
||
*/
|
||
void deliverLetter(String letter, String receiver);
|
||
|
||
/**
|
||
* 添加人
|
||
*/
|
||
void addPeople(People people);
|
||
}
|
||
|
||
@Data
|
||
static class PostOfficeImpl implements PostOffice {
|
||
private final Map<String, People> peopleMap = new HashMap<>();
|
||
|
||
/**
|
||
* 送信
|
||
*/
|
||
@Override
|
||
public void deliverLetter(String letter, String receiver) {
|
||
System.out.println("=>收信:邮局收到要寄的信");
|
||
|
||
People people = peopleMap.get(receiver);
|
||
|
||
System.out.println("=>送信:拿出地址查询收件人地址是:" + people.getAddress() + ",送信");
|
||
System.out.println("=>收信人看信:");
|
||
|
||
people.receiveLetter(letter);
|
||
}
|
||
|
||
/**
|
||
* 添加人
|
||
*/
|
||
@Override
|
||
public void addPeople(People people) {
|
||
peopleMap.put(people.getClass().getSimpleName(), people);
|
||
}
|
||
}
|
||
|
||
|
||
@Getter
|
||
static class People {
|
||
private final String address;
|
||
protected PostOffice postOffice;
|
||
|
||
public People(PostOffice postOffice, String address) {
|
||
this.postOffice = postOffice;
|
||
this.address = address;
|
||
}
|
||
|
||
/**
|
||
* 收到信
|
||
*
|
||
* @param letter 信的内容
|
||
*/
|
||
public void receiveLetter(String letter) {
|
||
System.out.println(letter);
|
||
}
|
||
|
||
/**
|
||
* 发送信
|
||
*
|
||
* @param letter 信内容
|
||
* @param receiver 收件人
|
||
*/
|
||
public void sendLetter(String letter, String receiver) {
|
||
postOffice.deliverLetter(letter, receiver);
|
||
}
|
||
}
|
||
|
||
static class Me extends People {
|
||
public Me(PostOffice postOffice, String address) {
|
||
super(postOffice, address);
|
||
}
|
||
}
|
||
|
||
static class You extends People {
|
||
public You(PostOffice postOffice, String address) {
|
||
super(postOffice, address);
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 运行结果:
|
||
|
||
```java
|
||
=>收信:邮局收到要寄的信
|
||
=>送信:拿出地址查询收件人地址是:在地球北边,送信
|
||
=>收信人看信:
|
||
我的消息
|
||
---------------分隔线---------------
|
||
=>收信:邮局收到要寄的信
|
||
=>送信:拿出地址查询收件人地址是:在地球北边,送信
|
||
=>收信人看信:
|
||
你的回信
|
||
---------------分隔线---------------
|
||
=>收信:邮局收到要寄的信
|
||
=>送信:拿出地址查询收件人地址是:在地球北边,送信
|
||
=>收信人看信:
|
||
哈哈哈哈哈哈哈哈哈
|
||
```
|
||
|
||
## 迭代器模式---行为型
|
||
|
||
**定义:**提供一种方法顺序访问一个聚合对象中的哥哥元素,而不是暴露其内部的表示。
|
||
|
||
![image-20250203173419155](./images/设计模式-v2/image-20250203173419155.png)
|
||
|
||
需要角色:抽象迭代器、具体迭代器、抽象聚合类、具体聚合类。
|
||
|
||
### 简单示例
|
||
|
||
#### 示例代码
|
||
|
||
```java
|
||
public class Iterator {
|
||
|
||
public static void main(String[] args) {
|
||
ListContainer listContainer = new ListContainer();
|
||
listContainer.add("序号1");
|
||
listContainer.add("序号2");
|
||
listContainer.add("序号3");
|
||
listContainer.add("序号4");
|
||
|
||
MyIterator iterator = listContainer.iterator();
|
||
while (iterator.hasNext()) {
|
||
System.out.println(iterator.next());
|
||
}
|
||
}
|
||
|
||
// 迭代器接口
|
||
interface MyIterator {
|
||
|
||
boolean hasNext();
|
||
|
||
Object next();
|
||
}
|
||
|
||
// 定义容器
|
||
interface MyContainer {
|
||
void add(Object o);
|
||
|
||
void remove(Object o);
|
||
|
||
MyIterator iterator();
|
||
}
|
||
|
||
// 列表操作容器
|
||
static class ListContainer implements MyContainer {
|
||
private final List<Object> list = new ArrayList<>();
|
||
|
||
@Override
|
||
public void add(Object o) {
|
||
list.add(o);
|
||
}
|
||
|
||
@Override
|
||
public void remove(Object o) {
|
||
list.remove(o);
|
||
}
|
||
|
||
@Override
|
||
public MyIterator iterator() {
|
||
return new MyIteratorImpl();
|
||
}
|
||
|
||
class MyIteratorImpl implements MyIterator {
|
||
|
||
private int index = 0;
|
||
|
||
@Override
|
||
public boolean hasNext() {
|
||
return index < list.size();
|
||
}
|
||
|
||
@Override
|
||
public Object next() {
|
||
Object object = list.get(index);
|
||
index++;
|
||
return object;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 运行结果:
|
||
|
||
```java
|
||
序号1
|
||
序号2
|
||
序号3
|
||
序号4
|
||
```
|
||
|
||
---
|
||
|
||
## 访问者模式---行为型
|
||
|
||
访问者模式(Visitor Pattern)是一种行为设计模式,它允许你在不修改元素类的前提下,定义新的操作。通过使用访问者模式,可以将操作和元素的结构分离,从而让你在不修改元素类的情况下,向其中添加新的操作。
|
||
|
||
![image-20250206163950552](./images/设计模式-v2/image-20250206163950552.png)
|
||
|
||
**需要角色**
|
||
|
||
**Element(元素)**:所有的元素类都需要实现此接口,它定义了`accept()`方法来接受访问者的访问。
|
||
|
||
**ConcreteElement(具体元素)**:这是实现Element接口的类,代表具体的对象,可以是任何你希望执行操作的对象。
|
||
|
||
**Visitor(访问者)**:这个接口定义了对所有元素类的访问方法。
|
||
|
||
**ConcreteVisitor(具体访问者)**:这是实现Visitor接口的类,具体执行对元素的操作。
|
||
|
||
**Object Structure(对象结构)**:一个包含所有元素对象的容器。它遍历所有元素对象并调用它们的`accept()`方法,传入访问者进行操作。
|
||
|
||
### 简单示例
|
||
|
||
#### 代码示例
|
||
|
||
```java
|
||
public class VisitorDemo1 {
|
||
public static void main(String[] args) {
|
||
BusinessReport report = new BusinessReport();
|
||
System.out.println("-------------------CEO-------------------");
|
||
report.showReport(new CEOVisitor());
|
||
|
||
System.out.println("-------------------CTO-------------------");
|
||
report.showReport(new CTOVisitor());
|
||
}
|
||
|
||
// 访问者
|
||
interface Visitor {
|
||
/**
|
||
* 访问者-工程师
|
||
*/
|
||
void visit(Engineer engineer);
|
||
|
||
/**
|
||
* 访问者-经理
|
||
*/
|
||
void visit(Manger manger);
|
||
}
|
||
|
||
// 具体访问者-CEO
|
||
static class CEOVisitor implements Visitor {
|
||
|
||
/**
|
||
* 访问者-工程师
|
||
*
|
||
* @param engineer 工程师
|
||
*/
|
||
@Override
|
||
public void visit(Engineer engineer) {
|
||
System.out.println("工程师:" + engineer.name + ",KPI:" + engineer.kpi);
|
||
}
|
||
|
||
/**
|
||
* 访问者-经理
|
||
*
|
||
* @param manger 经理
|
||
*/
|
||
@Override
|
||
public void visit(Manger manger) {
|
||
System.out.println("经理:" + manger.name + ",KPI:" + manger.kpi);
|
||
}
|
||
}
|
||
|
||
// 具体访问者-CTO
|
||
static class CTOVisitor implements Visitor {
|
||
|
||
/**
|
||
* 访问者-工程师
|
||
*
|
||
* @param engineer 工程师
|
||
*/
|
||
@Override
|
||
public void visit(Engineer engineer) {
|
||
System.out.println("工程师:" + engineer.name + ",代码行数:" + engineer.getCodeLines());
|
||
}
|
||
|
||
/**
|
||
* 访问者-经理
|
||
*
|
||
* @param manger 经理
|
||
*/
|
||
@Override
|
||
public void visit(Manger manger) {
|
||
System.out.println("经理:" + manger.name + ",产品数:" + manger.getProducts());
|
||
}
|
||
}
|
||
|
||
// 员工抽象
|
||
static abstract class Employee {
|
||
public String name;
|
||
public int kpi;
|
||
|
||
public Employee(String name) {
|
||
this.name = name;
|
||
this.kpi = new Random().nextInt(10);
|
||
}
|
||
|
||
// 接受访问者访问
|
||
public abstract void accept(Visitor visitor);
|
||
}
|
||
|
||
// 员工具体---工程师
|
||
static class Engineer extends Employee {
|
||
|
||
public Engineer(String name) {
|
||
super(name);
|
||
}
|
||
|
||
/**
|
||
* @param visitor 访问者
|
||
*/
|
||
@Override
|
||
public void accept(Visitor visitor) {
|
||
visitor.visit(this);
|
||
}
|
||
|
||
public int getCodeLines() {
|
||
return new Random().nextInt(10000);
|
||
}
|
||
}
|
||
|
||
// 员工具体---经理
|
||
static class Manger extends Employee {
|
||
|
||
public Manger(String name) {
|
||
super(name);
|
||
}
|
||
|
||
/**
|
||
* @param visitor 访问者
|
||
*/
|
||
@Override
|
||
public void accept(Visitor visitor) {
|
||
visitor.visit(this);
|
||
}
|
||
|
||
public int getProducts() {
|
||
return new Random().nextInt(10);
|
||
}
|
||
}
|
||
|
||
// 员工报表类
|
||
static class BusinessReport {
|
||
private final List<Employee> employeeList = new ArrayList<>();
|
||
|
||
public BusinessReport() {
|
||
employeeList.add(new Manger("经理-A"));
|
||
employeeList.add(new Manger("经理-B"));
|
||
employeeList.add(new Manger("经理-C"));
|
||
employeeList.add(new Manger("经理-D"));
|
||
employeeList.add(new Manger("经理-E"));
|
||
}
|
||
|
||
public void showReport(Visitor visitor) {
|
||
for (Employee employee : employeeList) {
|
||
employee.accept(visitor);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 运行结果:
|
||
|
||
```java
|
||
-------------------CEO-------------------
|
||
经理:经理-A,KPI:9
|
||
经理:经理-B,KPI:6
|
||
经理:经理-C,KPI:7
|
||
经理:经理-D,KPI:6
|
||
经理:经理-E,KPI:9
|
||
-------------------CTO-------------------
|
||
经理:经理-A,产品数:7
|
||
经理:经理-B,产品数:4
|
||
经理:经理-C,产品数:9
|
||
经理:经理-D,产品数:9
|
||
经理:经理-E,产品数:2
|
||
```
|
||
|
||
---
|
||
|
||
## 解释器模式---行为型
|
||
|
||
---
|
||
|
||
## 责任链模式---行为型
|
||
|
||
主要有两个角色:抽象处理者(Handler)、具体处理者(Concrete Handler)
|
||
|
||
![image-20250202201204954](./images/设计模式-v2/image-20250202201204954.png)
|
||
|
||
### 简单示例
|
||
|
||
#### 代码示例
|
||
|
||
```java
|
||
public class Chain {
|
||
|
||
// 过滤垃圾请求,为了演示需要清除【垃圾,辣鸡,腊鸡】这些词
|
||
public static void main(String[] args) {
|
||
Handler handlerA = new ConcreteHandlerA();
|
||
Handler handlerB = new ConcreteHandlerB();
|
||
Handler handlerC = new ConcreteHandlerC();
|
||
|
||
// 设置责任链
|
||
handlerA.setNextHandler(handlerB);
|
||
handlerB.setNextHandler(handlerC);
|
||
|
||
// 发起请求
|
||
handlerA.handleRequest("过滤垃圾请求,为了演示需要清除【垃圾,辣鸡,腊鸡】这些词");
|
||
}
|
||
|
||
// ConcreteHandler类
|
||
static class ConcreteHandlerA extends Handler {
|
||
@Override
|
||
public void handleRequest(String request) {
|
||
// 处理"垃圾"
|
||
String updatedRequest = request.replaceAll("垃圾", "");
|
||
System.out.println("Handler A处理后: " + updatedRequest);
|
||
|
||
if (nextHandler != null) {
|
||
nextHandler.handleRequest(updatedRequest); // 传递修改后的请求
|
||
}
|
||
}
|
||
}
|
||
|
||
static class ConcreteHandlerB extends Handler {
|
||
@Override
|
||
public void handleRequest(String request) {
|
||
// 处理"辣鸡"
|
||
String updatedRequest = request.replaceAll("辣鸡", "");
|
||
System.out.println("Handler B处理后: " + updatedRequest);
|
||
|
||
if (nextHandler != null) {
|
||
nextHandler.handleRequest(updatedRequest); // 传递修改后的请求
|
||
}
|
||
}
|
||
}
|
||
|
||
static class ConcreteHandlerC extends Handler {
|
||
@Override
|
||
public void handleRequest(String request) {
|
||
// 处理"腊鸡"
|
||
String updatedRequest = request.replaceAll("腊鸡", "");
|
||
System.out.println("Handler C处理后: " + updatedRequest);
|
||
|
||
if (nextHandler != null) {
|
||
nextHandler.handleRequest(updatedRequest); // 传递修改后的请求
|
||
}
|
||
}
|
||
}
|
||
|
||
// Handler类
|
||
@Setter
|
||
abstract static class Handler {
|
||
protected Handler nextHandler;
|
||
|
||
public abstract void handleRequest(String request);
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 运行结果:
|
||
|
||
```java
|
||
Handler A处理后: 过滤请求,为了演示需要清除【,辣鸡,腊鸡】这些词
|
||
Handler B处理后: 过滤请求,为了演示需要清除【,,腊鸡】这些词
|
||
Handler C处理后: 过滤请求,为了演示需要清除【,,】这些词
|
||
```
|
||
|