# 设计模式

设计模式是对许多业务和算法的抽象，因此学习起来具有一定的难度。短时间内掌握是不可能的，需要通过不断的实践和理解来积累经验。对于已经在职场上工作，但后期才开始学习设计模式的人来说，可能会面临更多的挑战。

在学习设计模式时，很多概念趋于理论化，且种类繁多（设计模式总共有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结构图。
- 装饰角色：继承或者实现**抽象组件**这是最关键的地方。
- 具体装饰角色：可以有多个实现或者继承**装饰角色**。