diff --git a/README/images/设计模式-v2/image-20250201164040235.png b/README/images/设计模式-v2/image-20250201164040235.png new file mode 100644 index 0000000..dd89a71 Binary files /dev/null and b/README/images/设计模式-v2/image-20250201164040235.png differ diff --git a/README/images/设计模式-v2/image-20250201173433406.png b/README/images/设计模式-v2/image-20250201173433406.png new file mode 100644 index 0000000..ceb7494 Binary files /dev/null and b/README/images/设计模式-v2/image-20250201173433406.png differ diff --git a/README/images/设计模式-v2/image-20250201175728138.png b/README/images/设计模式-v2/image-20250201175728138.png new file mode 100644 index 0000000..f209eb1 Binary files /dev/null and b/README/images/设计模式-v2/image-20250201175728138.png differ diff --git a/README/设计模式-v2.md b/README/设计模式-v2.md new file mode 100644 index 0000000..5884d2b --- /dev/null +++ b/README/设计模式-v2.md @@ -0,0 +1,314 @@ +# 设计模式 + +设计模式是对许多业务和算法的抽象,因此学习起来具有一定的难度。短时间内掌握是不可能的,需要通过不断的实践和理解来积累经验。对于已经在职场上工作,但后期才开始学习设计模式的人来说,可能会面临更多的挑战。 + +在学习设计模式时,很多概念趋于理论化,且种类繁多(设计模式总共有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 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结构图。 +- 装饰角色:继承或者实现**抽象组件**这是最关键的地方。 +- 具体装饰角色:可以有多个实现或者继承**装饰角色**。 \ No newline at end of file diff --git a/README/设计模式.md b/README/设计模式.md index 67f21e9..a51864b 100644 --- a/README/设计模式.md +++ b/README/设计模式.md @@ -374,8 +374,6 @@ public class Client { - **工厂方法模式**:通过子类来决定产品的创建,适合产品种类较多时,且产品可能会变化。 - **抽象工厂模式**:提供多个相关的产品的创建接口,适合需要创建一系列相关产品的场景。 - - ## 观察者模式 观察者模式是一种行为设计模式,它允许一个对象(被观察者)在其状态发生变化时,自动通知所有依赖于它的对象(观察者),而不需要知道这些观察者的具体细节。其主要思想是实现“低耦合”,即对象之间的关系通过接口进行松散连接。为了避免使用过时的类,我们可以手动实现观察者模式。我们需要定义一个“观察者”接口和一个“被观察者”接口,并在被观察者中维护一个观察者的列表,通知观察者更新状态。 @@ -483,7 +481,7 @@ public interface Subject { #### 主体实现 ```java -import cn.bunny.pattern3.observer.Observer; +import cn.bunny.pattern3.demo1.observer.Observer; import java.util.ArrayList; import java.util.List; @@ -526,11 +524,11 @@ public class WeatherStationSubject implements Subject { ### 运行 ```java -import cn.bunny.pattern3.observer.Observer; -import cn.bunny.pattern3.observer.Observer1; -import cn.bunny.pattern3.observer.Observer2; -import cn.bunny.pattern3.observer.Observer3; -import cn.bunny.pattern3.subject.WeatherStationSubject; +import cn.bunny.pattern3.demo1.observer.Observer; +import cn.bunny.pattern3.demo1.observer.Observer1; +import cn.bunny.pattern3.demo1.observer.Observer2; +import cn.bunny.pattern3.demo1.observer.Observer3; +import cn.bunny.pattern3.demo1.subject.WeatherStationSubject; public class Main { public static void main(String[] args) { @@ -662,17 +660,17 @@ public class FilterCameraDecorator extends CameraDecorator { public class Main { public static void main(String[] args) { System.out.println("------------------执行简单的拍照-------------------"); - + TakePhotoCamera takePhotoCamera = new TakePhotoCamera(); takePhotoCamera.operation(); System.out.println("-------------------需要美颜功能------------------"); - + BeautyCameraDecorator beautyCameraDecorator = new BeautyCameraDecorator(takePhotoCamera); beautyCameraDecorator.operation(); System.out.println("-------------------需要美颜功能之后滤镜------------------"); - + FilterCameraDecorator filterCameraDecorator = new FilterCameraDecorator(beautyCameraDecorator); filterCameraDecorator.operation(); } diff --git a/pattern/src/main/java/cn/bunny/pattern3/Main.java b/pattern/src/main/java/cn/bunny/pattern3/demo1/Main.java similarity index 76% rename from pattern/src/main/java/cn/bunny/pattern3/Main.java rename to pattern/src/main/java/cn/bunny/pattern3/demo1/Main.java index a76cf55..c079322 100644 --- a/pattern/src/main/java/cn/bunny/pattern3/Main.java +++ b/pattern/src/main/java/cn/bunny/pattern3/demo1/Main.java @@ -1,11 +1,11 @@ -package cn.bunny.pattern3; +package cn.bunny.pattern3.demo1; -import cn.bunny.pattern3.observer.Observer; -import cn.bunny.pattern3.observer.Observer1; -import cn.bunny.pattern3.observer.Observer2; -import cn.bunny.pattern3.observer.Observer3; -import cn.bunny.pattern3.subject.WeatherStationSubject; +import cn.bunny.pattern3.demo1.observer.Observer; +import cn.bunny.pattern3.demo1.observer.Observer1; +import cn.bunny.pattern3.demo1.observer.Observer2; +import cn.bunny.pattern3.demo1.observer.Observer3; +import cn.bunny.pattern3.demo1.subject.WeatherStationSubject; public class Main { public static void main(String[] args) { diff --git a/pattern/src/main/java/cn/bunny/pattern3/observer/Observer.java b/pattern/src/main/java/cn/bunny/pattern3/demo1/observer/Observer.java similarity index 86% rename from pattern/src/main/java/cn/bunny/pattern3/observer/Observer.java rename to pattern/src/main/java/cn/bunny/pattern3/demo1/observer/Observer.java index 3d6461b..1b92cfb 100644 --- a/pattern/src/main/java/cn/bunny/pattern3/observer/Observer.java +++ b/pattern/src/main/java/cn/bunny/pattern3/demo1/observer/Observer.java @@ -1,4 +1,4 @@ -package cn.bunny.pattern3.observer; +package cn.bunny.pattern3.demo1.observer; /** * 观察者接口 diff --git a/pattern/src/main/java/cn/bunny/pattern3/observer/Observer1.java b/pattern/src/main/java/cn/bunny/pattern3/demo1/observer/Observer1.java similarity index 90% rename from pattern/src/main/java/cn/bunny/pattern3/observer/Observer1.java rename to pattern/src/main/java/cn/bunny/pattern3/demo1/observer/Observer1.java index 6fb825b..05168be 100644 --- a/pattern/src/main/java/cn/bunny/pattern3/observer/Observer1.java +++ b/pattern/src/main/java/cn/bunny/pattern3/demo1/observer/Observer1.java @@ -1,4 +1,4 @@ -package cn.bunny.pattern3.observer; +package cn.bunny.pattern3.demo1.observer; public class Observer1 implements Observer { diff --git a/pattern/src/main/java/cn/bunny/pattern3/observer/Observer2.java b/pattern/src/main/java/cn/bunny/pattern3/demo1/observer/Observer2.java similarity index 90% rename from pattern/src/main/java/cn/bunny/pattern3/observer/Observer2.java rename to pattern/src/main/java/cn/bunny/pattern3/demo1/observer/Observer2.java index d736c6e..08da1fa 100644 --- a/pattern/src/main/java/cn/bunny/pattern3/observer/Observer2.java +++ b/pattern/src/main/java/cn/bunny/pattern3/demo1/observer/Observer2.java @@ -1,4 +1,4 @@ -package cn.bunny.pattern3.observer; +package cn.bunny.pattern3.demo1.observer; public class Observer2 implements Observer { diff --git a/pattern/src/main/java/cn/bunny/pattern3/observer/Observer3.java b/pattern/src/main/java/cn/bunny/pattern3/demo1/observer/Observer3.java similarity index 90% rename from pattern/src/main/java/cn/bunny/pattern3/observer/Observer3.java rename to pattern/src/main/java/cn/bunny/pattern3/demo1/observer/Observer3.java index b984e8b..153dec7 100644 --- a/pattern/src/main/java/cn/bunny/pattern3/observer/Observer3.java +++ b/pattern/src/main/java/cn/bunny/pattern3/demo1/observer/Observer3.java @@ -1,4 +1,4 @@ -package cn.bunny.pattern3.observer; +package cn.bunny.pattern3.demo1.observer; public class Observer3 implements Observer { diff --git a/pattern/src/main/java/cn/bunny/pattern3/subject/Subject.java b/pattern/src/main/java/cn/bunny/pattern3/demo1/subject/Subject.java similarity index 66% rename from pattern/src/main/java/cn/bunny/pattern3/subject/Subject.java rename to pattern/src/main/java/cn/bunny/pattern3/demo1/subject/Subject.java index 5c3dff8..227d4f4 100644 --- a/pattern/src/main/java/cn/bunny/pattern3/subject/Subject.java +++ b/pattern/src/main/java/cn/bunny/pattern3/demo1/subject/Subject.java @@ -1,6 +1,6 @@ -package cn.bunny.pattern3.subject; +package cn.bunny.pattern3.demo1.subject; -import cn.bunny.pattern3.observer.Observer; +import cn.bunny.pattern3.demo1.observer.Observer; /** * 被观察者接口 diff --git a/pattern/src/main/java/cn/bunny/pattern3/subject/WeatherStationSubject.java b/pattern/src/main/java/cn/bunny/pattern3/demo1/subject/WeatherStationSubject.java similarity index 90% rename from pattern/src/main/java/cn/bunny/pattern3/subject/WeatherStationSubject.java rename to pattern/src/main/java/cn/bunny/pattern3/demo1/subject/WeatherStationSubject.java index 20d93a5..1dc6cd3 100644 --- a/pattern/src/main/java/cn/bunny/pattern3/subject/WeatherStationSubject.java +++ b/pattern/src/main/java/cn/bunny/pattern3/demo1/subject/WeatherStationSubject.java @@ -1,7 +1,7 @@ -package cn.bunny.pattern3.subject; +package cn.bunny.pattern3.demo1.subject; -import cn.bunny.pattern3.observer.Observer; +import cn.bunny.pattern3.demo1.observer.Observer; import java.util.ArrayList; import java.util.List; diff --git a/pattern/src/main/java/cn/bunny/pattern3/demo2/ObserverDemo.java b/pattern/src/main/java/cn/bunny/pattern3/demo2/ObserverDemo.java new file mode 100644 index 0000000..fffbcbf --- /dev/null +++ b/pattern/src/main/java/cn/bunny/pattern3/demo2/ObserverDemo.java @@ -0,0 +1,84 @@ +package cn.bunny.pattern3.demo2; + +import java.util.ArrayList; +import java.util.List; + +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); + } + } + } +} +