From 3ede03600924e0c9c31b20a4fd9eb0368bda6f67 Mon Sep 17 00:00:00 2001 From: Bunny <1319900154@qq.com> Date: Mon, 3 Feb 2025 16:25:11 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=A4=96=E8=A7=82=E6=A8=A1=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../设计模式-v2/image-20250203154216552.png | Bin 0 -> 18746 bytes README/设计模式-v2.md | 1734 +++++++++-------- .../main/java/cn/bunny/pattern10/Facade.java | 51 + 3 files changed, 962 insertions(+), 823 deletions(-) create mode 100644 README/images/设计模式-v2/image-20250203154216552.png create mode 100644 pattern/src/main/java/cn/bunny/pattern10/Facade.java diff --git a/README/images/设计模式-v2/image-20250203154216552.png b/README/images/设计模式-v2/image-20250203154216552.png new file mode 100644 index 0000000000000000000000000000000000000000..d2e7815274ed7ec3ba86816cb0aa8e57d0ea7bbb GIT binary patch literal 18746 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

dW^^)e=;rG|j%L6^CM6 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 literal 0 HcmV?d00001 diff --git a/README/设计模式-v2.md b/README/设计模式-v2.md index a8946e5..6fee5fd 100644 --- a/README/设计模式-v2.md +++ b/README/设计模式-v2.md @@ -10,659 +10,7 @@ --- -## 策略模式 - -### 常见应用场景 - -策略模式广泛应用于支付、计算、文件压缩、登录等场景,尤其是在游戏中,如王者荣耀和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 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结构图。 -- 装饰角色:继承或者实现**抽象组件**这是最关键的地方。 -- 具体装饰角色:可以有多个实现或者继承**装饰角色**。 - -### 简单示例 - -需要做一个抽象的相机功能,相机包含拍照功能(这是肯定的),之后随着业务需求要求相机有美颜功能,在这之后还要有滤镜功能,客户还需要延迟摄影功能。 - -![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**:客户端,负责创建并配置命令对象,将命令与接收者绑定,并传递给调用者执行。 - -### 简单示例 - -![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 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 -开始烤鸡翅。。。 -开始烤串。。。 -``` - ---- - -## 工厂模式 +## 工厂模式---创建型 ### 工厂模式(Factory Pattern)介绍 @@ -745,7 +93,7 @@ public class Client { --- -## 单例模式 +## 单例模式---创建型 ### 懒汉模式 @@ -875,6 +223,201 @@ public class Main { } ``` +## 原型模式---创建型 + +![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) @@ -1042,7 +585,247 @@ 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) @@ -1315,119 +1098,294 @@ public class Adapter3 { --- -## 外观模式 +## 组合模式---结构型 --- -## 组合模式 +## 享元模式---结构型 --- -## 状态模式 +## 代理模式---结构型 --- -## 模板方法模式 +## 桥接模式---结构型 --- -## 备忘录模式 +## 策略模式---行为型 + +### 常见应用场景 + +策略模式广泛应用于支付、计算、文件压缩、登录等场景,尤其是在游戏中,如王者荣耀和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-20250202214232289](./images/设计模式-v2/image-20250202214232289.png) - -需要三个角色:抽象原型类(Abstract Prototype)、具体原型类(Concrete Prototype)、访问类(Client) +![image-20250201175728138](./images/设计模式-v2/image-20250201175728138.png) ### 简单示例 -提示:需要做深克隆,当类中还存在另一个类时 +其中主题中有3个方法,添加(或者理解成注册都可以)、移出、通知,差不多都是这三个方法,其中添加可以理解成注册加入总之是往数组中添加观察者。 -#### 错误示例代码 - -当我们对school对象进行设置时,对`resume1`进行设置结果`resume`也发生了改变。需要修改`Resume`类中的`clone`方法 +#### 代码实现 ```java -public class Prototype { +public class ObserverDemo { public static void main(String[] args) { - Resume resume = new Resume(); - resume.name = "Bunny"; - resume.position = "架构师"; - resume.salary = 15000; + // 定义的主题 + News news = new News(); - School school = new School(); - school.schoolName = "江南大学"; - school.time = "2025年2月2日21:38:07"; - resume.school = school; - System.out.println(resume); + // 观察者 + SisterObserver sisterObserver = new SisterObserver(); + GirlfriendObserver girlfriendObserver = new GirlfriendObserver(); - Resume resume1 = resume.clone(); - resume1.salary = 19000; - resume1.school.schoolName = "清华大学"; - System.out.println(resume1); + // 添加观察者 + news.addObserver(sisterObserver); + news.notifyObservers("添加了妹妹"); - Resume resume2 = resume.clone(); - resume2.salary = 20000; - System.out.println(resume2); + System.out.println("\n-----------------分割线-----------------\n"); - System.out.println(resume1 == resume2);// false - System.out.println(resume1.school == resume2.school);// true + // 添加女朋友 + news.addObserver(girlfriendObserver); + news.notifyObservers("添加了女朋友"); + + System.out.println("\n-----------------分割线-----------------\n"); + news.removeObserver(girlfriendObserver); + news.notifyObservers("需要和妹妹说点悄悄话,将女朋友移除了,这时女朋友听不见我们说话。。。"); } - @Data - static class Resume implements Cloneable { - private String name; - private String position; - private Integer salary; - private School school; + // 观察者接口 + @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 Resume clone() { - try { - return (Resume) super.clone(); - } catch (CloneNotSupportedException e) { - throw new AssertionError(); - } + public void update(String message) { + System.out.println("SisterObserver 接受到消息:" + message); } } - @Data - static class School implements Cloneable { - private String schoolName; - private String time; + // 女朋友观察者 + static class GirlfriendObserver implements Observer { + @Override + public void update(String message) { + System.out.println("GirlfriendObserver 接受到消息:" + message); + } + } + + // 主题类 + static class News implements Subject { + + private final List observerList = new ArrayList<>(); @Override - public School clone() { - try { - return (School) super.clone(); - } catch (CloneNotSupportedException e) { - throw new AssertionError(); + 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); } } } @@ -1437,130 +1395,260 @@ public class Prototype { #### 运行结果: ```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 +SisterObserver 接受到消息:添加了妹妹 + +-----------------分割线----------------- + +SisterObserver 接受到消息:添加了女朋友 +GirlfriendObserver 接受到消息:添加了女朋友 + +-----------------分割线----------------- + +SisterObserver 接受到消息:需要和妹妹说点悄悄话,将女朋友移除了,这时女朋友听不见我们说话。。。 ``` -#### 正确示例代码 +--- -##### 修改`conle` +## 命令模式---行为型 + +**Command**:定义执行请求的接口(或抽象类)。 + +**ConcreteCommand**:实现命令接口并具体化执行请求的过程,通常还会持有接收者对象。 + +**Receiver**:具体的对象,完成实际的操作任务。 + +**Invoker**:调用命令的对象,触发命令的执行。 + +**Client**:客户端,负责创建并配置命令对象,将命令与接收者绑定,并传递给调用者执行。 + +### 简单示例 + +![image-20250201205350467](./images/设计模式-v2/image-20250201205350467.png) + +#### 示例代码 ```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 class CommandDemo { public static void main(String[] args) { - Resume resume = new Resume(); - resume.name = "Bunny"; - resume.position = "架构师"; - resume.salary = 15000; + Receiver receiver = new Receiver(); - School school = new School(); - school.schoolName = "江南大学"; - school.time = "2025年2月2日21:38:07"; - resume.school = school; - System.out.println(resume); + ConcreteCommand concreteCommand = new ConcreteCommand(receiver); - 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 + Invoker invoker = new Invoker(); + invoker.setCommand(concreteCommand); + invoker.invoke(); } - @Data - static class Resume implements Cloneable { - private String name; - private String position; - private Integer salary; - private School school; + // 命令接口 + interface Command { - @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(); - } + /** + * 执行方法 + */ + void execute(); + } - return resume; + // 接受者 + static class Receiver { + public void action() { + System.out.println("接受者 执行。。。"); } } - @Data - static class School implements Cloneable { - private String schoolName; - private String time; + // 具体的执行命令 + static class ConcreteCommand implements Command { + private final Receiver receiver; + + public ConcreteCommand(Receiver receiver) { + this.receiver = receiver; + } + + /** + * 执行方法 + */ @Override - public School clone() { - try { - return (School) super.clone(); - } catch (CloneNotSupportedException e) { - throw new AssertionError(); - } + 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 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 +开始烤鸡翅。。。 +开始烤串。。。 +``` + +--- + +## 状态模式---行为型 + +--- + +## 模板方法模式---行为型 + +将定义好的按步骤执行的内容进行封装,模板方法是比较单间的设计模式,是代码复用的基本技术,在类库中尤其重要,遵循:“抽象类应当拥有尽可能多的可能性,应当拥有尽可能少的数据”。 + +需要的角色:抽象类(Abstract Class)、具体类(Concrete Class)。 + +比如做一些比较固定的事情(支付流程处理),但是其中几项内容可能会发生改变。 + +### 简单示例 + +#### 示例代码 + #### 运行结果: ```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 + ``` --- -## 桥接模式 - - +## 备忘录模式---行为型 --- -## 责任链模式-未完成。。。 +## 中介者模式---行为型 + +--- + +## 迭代器模式---行为型 + +--- + +## 访问者模式---行为型 + +--- + +## 解释器模式---行为型 + +--- + +## 责任链模式---行为型-未完成。。。 主要有两个角色:抽象处理者(Handler)、具体处理者(Concrete Handler) diff --git a/pattern/src/main/java/cn/bunny/pattern10/Facade.java b/pattern/src/main/java/cn/bunny/pattern10/Facade.java new file mode 100644 index 0000000..bcb9a69 --- /dev/null +++ b/pattern/src/main/java/cn/bunny/pattern10/Facade.java @@ -0,0 +1,51 @@ +package cn.bunny.pattern10; + +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(); + } + } +}