feat: 重写观察者模式
This commit is contained in:
parent
fb7360c387
commit
b577e71956
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 |
|
@ -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结构图。
|
||||
- 装饰角色:继承或者实现**抽象组件**这是最关键的地方。
|
||||
- 具体装饰角色:可以有多个实现或者继承**装饰角色**。
|
|
@ -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) {
|
||||
|
|
|
@ -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) {
|
|
@ -1,4 +1,4 @@
|
|||
package cn.bunny.pattern3.observer;
|
||||
package cn.bunny.pattern3.demo1.observer;
|
||||
|
||||
/**
|
||||
* 观察者接口
|
|
@ -1,4 +1,4 @@
|
|||
package cn.bunny.pattern3.observer;
|
||||
package cn.bunny.pattern3.demo1.observer;
|
||||
|
||||
public class Observer1 implements Observer {
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package cn.bunny.pattern3.observer;
|
||||
package cn.bunny.pattern3.demo1.observer;
|
||||
|
||||
public class Observer2 implements Observer {
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package cn.bunny.pattern3.observer;
|
||||
package cn.bunny.pattern3.demo1.observer;
|
||||
|
||||
public class Observer3 implements Observer {
|
||||
|
|
@ -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;
|
||||
|
||||
/**
|
||||
* 被观察者接口
|
|
@ -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;
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue