2025-02-01 18:17:20 +08:00
|
|
|
|
# 设计模式
|
|
|
|
|
|
|
|
|
|
设计模式是对许多业务和算法的抽象,因此学习起来具有一定的难度。短时间内掌握是不可能的,需要通过不断的实践和理解来积累经验。对于已经在职场上工作,但后期才开始学习设计模式的人来说,可能会面临更多的挑战。
|
|
|
|
|
|
|
|
|
|
在学习设计模式时,很多概念趋于理论化,且种类繁多(设计模式总共有23种),如果没有进行系统的梳理,可能很难直接应用到实际场景中。
|
|
|
|
|
|
|
|
|
|
设计模式中的抽象类通常是接口或抽象类,这些类的实现会根据具体的业务需求进行调整,因而不一定是唯一的实现方式。
|
|
|
|
|
|
|
|
|
|
在我学习过程中,我试图将所学的内容总结下来,但由于篇幅有限,无法一一列举所有场景,只能举出一些常见的例子。
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
## 策略模式
|
|
|
|
|
|
|
|
|
|
### 常见应用场景
|
|
|
|
|
|
|
|
|
|
策略模式广泛应用于支付、计算、文件压缩、登录等场景,尤其是在游戏中,如王者荣耀和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 接受到消息:需要和妹妹说点悄悄话,将女朋友移除了,这时女朋友听不见我们说话。。。
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
## 装饰者模式
|
|
|
|
|
|
|
|
|
|
一共有四个角色。
|
|
|
|
|
|
|
|
|
|
- 抽象组件:一般是最原始、最基础的对象。
|
|
|
|
|
- 具体组件:一般是最原始最基础的实现对象,可以有多个(只是数量不多),可以大致看下`InputStream`UML结构图。
|
|
|
|
|
- 装饰角色:继承或者实现**抽象组件**这是最关键的地方。
|
2025-02-01 19:05:08 +08:00
|
|
|
|
- 具体装饰角色:可以有多个实现或者继承**装饰角色**。
|
|
|
|
|
|
|
|
|
|
### 简单示例
|
|
|
|
|
|
|
|
|
|
需要做一个抽象的相机功能,相机包含拍照功能(这是肯定的),之后随着业务需求要求相机有美颜功能,在这之后还要有滤镜功能,客户还需要延迟摄影功能。
|
|
|
|
|
|
|
|
|
|
![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
|
|
|
|
|
相机拍照。。。
|
|
|
|
|
美颜功能。。。
|
|
|
|
|
滤镜效果。。。
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
## 命令模式
|
|
|
|
|
|
|
|
|
|
**Command**:定义执行请求的接口(或抽象类)。
|
|
|
|
|
|
|
|
|
|
**ConcreteCommand**:实现命令接口并具体化执行请求的过程,通常还会持有接收者对象。
|
|
|
|
|
|
|
|
|
|
**Receiver**:具体的对象,完成实际的操作任务。
|
|
|
|
|
|
|
|
|
|
**Invoker**:调用命令的对象,触发命令的执行。
|
|
|
|
|
|
|
|
|
|
**Client**:客户端,负责创建并配置命令对象,将命令与接收者绑定,并传递给调用者执行。
|
|
|
|
|
|
2025-02-02 21:22:49 +08:00
|
|
|
|
### 简单示例
|
|
|
|
|
|
|
|
|
|
![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
|
|
|
|
|
开始烤鸡翅。。。
|
|
|
|
|
开始烤串。。。
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
---
|
2025-02-01 19:05:08 +08:00
|
|
|
|
|
2025-02-02 21:22:49 +08:00
|
|
|
|
## 工厂模式
|
2025-02-01 19:05:08 +08:00
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
## 单例模式
|
|
|
|
|
|
|
|
|
|
### 懒汉模式
|
|
|
|
|
|
|
|
|
|
#### 双重检查锁定(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();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
```
|
2025-02-01 20:32:09 +08:00
|
|
|
|
|
|
|
|
|
## 建造者模式
|
|
|
|
|
|
|
|
|
|
![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();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
2025-02-02 21:22:49 +08:00
|
|
|
|
#### 运行结果:
|
2025-02-01 20:32:09 +08:00
|
|
|
|
|
|
|
|
|
```java
|
|
|
|
|
CommandDemo.Computer(CPU=Low CPU, RAM=Low RAM, hardDrive=Low Driver)
|
|
|
|
|
|
|
|
|
|
-----------------分割线-----------------
|
|
|
|
|
|
|
|
|
|
CommandDemo.Computer(CPU=High CPU, RAM=High RAM, hardDrive=High Driver)
|
|
|
|
|
```
|
|
|
|
|
|
2025-02-02 21:49:23 +08:00
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
## 原型模式
|
|
|
|
|
|
|
|
|
|
![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
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
2025-02-02 21:22:49 +08:00
|
|
|
|
## 责任链模式-未完成。。。
|
|
|
|
|
|
2025-02-02 21:49:23 +08:00
|
|
|
|
主要有两个角色:抽象处理者(Handler)、具体处理者(Concrete Handler)
|
2025-02-02 21:22:49 +08:00
|
|
|
|
|
|
|
|
|
![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处理后: 过滤请求,为了演示需要清除【,,】这些词
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
###
|