diff --git a/README/images/设计模式-v2/image-20250203154216552.png b/README/images/设计模式-v2/image-20250203154216552.png new file mode 100644 index 0000000..d2e7815 Binary files /dev/null and b/README/images/设计模式-v2/image-20250203154216552.png differ 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(); + } + } +}