feat: 重写观察者模式

This commit is contained in:
Bunny 2025-02-01 18:17:20 +08:00
parent fb7360c387
commit b577e71956
13 changed files with 421 additions and 25 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

314
README/设计模式-v2.md Normal file
View File

@ -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<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结构图。
- 装饰角色:继承或者实现**抽象组件**这是最关键的地方。
- 具体装饰角色:可以有多个实现或者继承**装饰角色**。

View File

@ -374,8 +374,6 @@ public class Client {
- **工厂方法模式**:通过子类来决定产品的创建,适合产品种类较多时,且产品可能会变化。 - **工厂方法模式**:通过子类来决定产品的创建,适合产品种类较多时,且产品可能会变化。
- **抽象工厂模式**:提供多个相关的产品的创建接口,适合需要创建一系列相关产品的场景。 - **抽象工厂模式**:提供多个相关的产品的创建接口,适合需要创建一系列相关产品的场景。
## 观察者模式 ## 观察者模式
观察者模式是一种行为设计模式,它允许一个对象(被观察者)在其状态发生变化时,自动通知所有依赖于它的对象(观察者),而不需要知道这些观察者的具体细节。其主要思想是实现“低耦合”,即对象之间的关系通过接口进行松散连接。为了避免使用过时的类,我们可以手动实现观察者模式。我们需要定义一个“观察者”接口和一个“被观察者”接口,并在被观察者中维护一个观察者的列表,通知观察者更新状态。 观察者模式是一种行为设计模式,它允许一个对象(被观察者)在其状态发生变化时,自动通知所有依赖于它的对象(观察者),而不需要知道这些观察者的具体细节。其主要思想是实现“低耦合”,即对象之间的关系通过接口进行松散连接。为了避免使用过时的类,我们可以手动实现观察者模式。我们需要定义一个“观察者”接口和一个“被观察者”接口,并在被观察者中维护一个观察者的列表,通知观察者更新状态。
@ -483,7 +481,7 @@ public interface Subject {
#### 主体实现 #### 主体实现
```java ```java
import cn.bunny.pattern3.observer.Observer; import cn.bunny.pattern3.demo1.observer.Observer;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -526,11 +524,11 @@ public class WeatherStationSubject implements Subject {
### 运行 ### 运行
```java ```java
import cn.bunny.pattern3.observer.Observer; import cn.bunny.pattern3.demo1.observer.Observer;
import cn.bunny.pattern3.observer.Observer1; import cn.bunny.pattern3.demo1.observer.Observer1;
import cn.bunny.pattern3.observer.Observer2; import cn.bunny.pattern3.demo1.observer.Observer2;
import cn.bunny.pattern3.observer.Observer3; import cn.bunny.pattern3.demo1.observer.Observer3;
import cn.bunny.pattern3.subject.WeatherStationSubject; import cn.bunny.pattern3.demo1.subject.WeatherStationSubject;
public class Main { public class Main {
public static void main(String[] args) { public static void main(String[] args) {
@ -662,17 +660,17 @@ public class FilterCameraDecorator extends CameraDecorator {
public class Main { public class Main {
public static void main(String[] args) { public static void main(String[] args) {
System.out.println("------------------执行简单的拍照-------------------"); System.out.println("------------------执行简单的拍照-------------------");
TakePhotoCamera takePhotoCamera = new TakePhotoCamera(); TakePhotoCamera takePhotoCamera = new TakePhotoCamera();
takePhotoCamera.operation(); takePhotoCamera.operation();
System.out.println("-------------------需要美颜功能------------------"); System.out.println("-------------------需要美颜功能------------------");
BeautyCameraDecorator beautyCameraDecorator = new BeautyCameraDecorator(takePhotoCamera); BeautyCameraDecorator beautyCameraDecorator = new BeautyCameraDecorator(takePhotoCamera);
beautyCameraDecorator.operation(); beautyCameraDecorator.operation();
System.out.println("-------------------需要美颜功能之后滤镜------------------"); System.out.println("-------------------需要美颜功能之后滤镜------------------");
FilterCameraDecorator filterCameraDecorator = new FilterCameraDecorator(beautyCameraDecorator); FilterCameraDecorator filterCameraDecorator = new FilterCameraDecorator(beautyCameraDecorator);
filterCameraDecorator.operation(); filterCameraDecorator.operation();
} }

View File

@ -1,11 +1,11 @@
package cn.bunny.pattern3; package cn.bunny.pattern3.demo1;
import cn.bunny.pattern3.observer.Observer; import cn.bunny.pattern3.demo1.observer.Observer;
import cn.bunny.pattern3.observer.Observer1; import cn.bunny.pattern3.demo1.observer.Observer1;
import cn.bunny.pattern3.observer.Observer2; import cn.bunny.pattern3.demo1.observer.Observer2;
import cn.bunny.pattern3.observer.Observer3; import cn.bunny.pattern3.demo1.observer.Observer3;
import cn.bunny.pattern3.subject.WeatherStationSubject; import cn.bunny.pattern3.demo1.subject.WeatherStationSubject;
public class Main { public class Main {
public static void main(String[] args) { public static void main(String[] args) {

View File

@ -1,4 +1,4 @@
package cn.bunny.pattern3.observer; package cn.bunny.pattern3.demo1.observer;
/** /**
* 观察者接口 * 观察者接口

View File

@ -1,4 +1,4 @@
package cn.bunny.pattern3.observer; package cn.bunny.pattern3.demo1.observer;
public class Observer1 implements Observer { public class Observer1 implements Observer {

View File

@ -1,4 +1,4 @@
package cn.bunny.pattern3.observer; package cn.bunny.pattern3.demo1.observer;
public class Observer2 implements Observer { public class Observer2 implements Observer {

View File

@ -1,4 +1,4 @@
package cn.bunny.pattern3.observer; package cn.bunny.pattern3.demo1.observer;
public class Observer3 implements Observer { public class Observer3 implements Observer {

View File

@ -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;
/** /**
* 被观察者接口 * 被观察者接口

View File

@ -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.ArrayList;
import java.util.List; import java.util.List;

View File

@ -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<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);
}
}
}
}