# 设计模式

## 单例模式

### 懒汉模式

#### 双重检查锁定（DCL）

```java
public class Singleton {
    private static volatile Singleton instance;

    private Singleton() {
        // 构造函数私有化
    }

    public static Singleton getInstance() {
        if (instance == null) { // 第一次检查
            synchronized (Singleton.class) {
                if (instance == null) { // 第二次检查
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}
```

#### 静态内部类方式

利用 **静态内部类**（饿汉式）的特性来实现懒汉模式，并且可以保证线程安全。这种方式只有在调用 `getInstance()` 时才会加载内部类，从而实现懒加载。

```java
public class Singleton {
    private Singleton() {
        // 构造函数私有化
    }

    private static class SingletonHolder {
        private static final Singleton INSTANCE = new Singleton();
    }

    public static Singleton getInstance() {
        return SingletonHolder.INSTANCE;
    }
}
```

#### 适用场景

- 如果单例对象比较重，且只在程序中某些特定情况下才使用，懒汉模式可以带来性能优势。
- 在低并发环境或单线程环境下，懒汉模式使用较为简单，不会有多线程安全问题。
- 对于高并发且需要频繁访问单例的场景，推荐使用**静态内部类**或**饿汉模式**来避免懒汉模式可能带来的性能问题。

#### 总结

懒汉模式有时为了延迟初始化而牺牲了性能，特别是在多线程环境下。为了保证线程安全，可以采用双重检查锁定（DCL）或静态内部类的方式，而**静态内部类方式是最推荐的方式**
，它避免了同步开销，同时也能确保线程安全。

- **优点**：
    1. 延迟加载，节省资源。
    2. 内存优化，只有在需要时才实例化。
    3. 减少不必要的初始化开销。
- **缺点**：
    1. 传统懒汉模式线程不安全（多个线程可能会创建多个实例）。
    2. 使用同步机制会有性能开销，特别是在多线程环境下。
    3. 代码复杂性较高，容易引入错误。
    4. 不适合高并发场景，特别是频繁访问时会影响性能。

### 饿汉模式

**饿汉模式**（Eager Initialization）是单例模式的一种实现方式，在该方式中，单例实例在类加载时就已经创建完成，而不是在首次使用时才创建。换句话说，**饿汉模式**
的单例实例在类被加载时就会立即初始化，确保了单例模式的唯一性。

```java
public class Singleton {

    // 在类加载时就初始化单例对象
    private static final Singleton INSTANCE = new Singleton();

    // 私有构造函数，防止外部通过 new 创建实例
    private Singleton() {
    }

    // 提供全局访问点
    public static Singleton getInstance() {
        return INSTANCE;
    }
}
```

#### 适用场景

- **简单应用**：适合没有延迟初始化需求的小型应用，或者单例对象的创建非常轻量，不会影响系统性能的场景。
- **实例化不耗费太多资源**：如果单例对象的初始化过程非常轻量级且无须延迟初始化，可以使用饿汉模式。
- **类加载顺序固定**：如果不在乎单例对象在启动时是否初始化，且单例对象的初始化过程没有严重性能损失，可以选择饿汉模式。

#### 总结

- **优点**：简单、线程安全、性能高（没有锁机制）、实现方便。
- **缺点**：不支持延迟加载、可能会浪费资源（如果单例对象不常用时）。

饿汉模式是单例模式中最简单的实现方式，适用于大多数情况下单例对象的创建开销较小，且不需要延迟初始化的场景。如果单例对象的创建非常轻量且不依赖于后期加载时的资源，饿汉模式是一个不错的选择。

### 枚举类型实现

**枚举类型实现单例模式**（Enum Singleton）是实现单例模式的另一种方式，优点是更加简洁、可靠，并且避免了许多常见的单例实现方式（如懒汉模式和饿汉模式）可能出现的问题。使用枚举类型的单例实现方式自
**Java 5** 引入以来，已经成为了最推荐的单例模式实现方式之一。

**当你不需要懒加载或延迟初始化时，使用枚举实现单例模式是最理想的选择。**

```java
public enum Singleton {

    // 唯一实例
    INSTANCE;

    // 可以添加其他的方法
    public void someMethod() {
        System.out.println("This is a singleton instance method.");
    }
}
```

#### 使用示例

```java
public class Main {
    public static void main(String[] args) {
        // 获取单例对象
        Singleton singleton = Singleton.INSTANCE;

        // 调用单例方法
        singleton.someMethod();
    }
}
```

#### 总结

枚举类型实现单例模式是非常推荐的做法，尤其是在 Java 5 及以后的版本。它简单、线程安全、避免了反射和序列化带来的问题，且保证了单例模式的正确性。对于绝大多数的单例模式实现需求，枚举类型是最安全、最简洁、最优雅的解决方案。

## 工厂模式

工厂模式（Factory Pattern）是创建型设计模式的一种，它提供了一种创建对象的方式，而不需要暴露具体的类实例化过程。

工厂模式适用于以下场景：

- **对象创建逻辑复杂**：当对象的创建过程比较复杂，包含多个初始化步骤时。
- **类的创建与实现解耦**：客户端只关心产品的接口，而不关心具体实现。
- **动态选择不同类型的对象**：需要根据不同条件动态选择创建的对象类型。
- **产品种类变化频繁**：产品的类型变化较多时，使用工厂模式能使扩展更加灵活。
- **避免客户端直接实例化**：通过工厂封装对象的创建过程，减少客户端与具体实现的耦合。

### 1. **简单工厂模式（Simple Factory Pattern）**

简单工厂模式是工厂模式的一种简单形式，**它并不属于设计模式中的结构**，它是通过一个工厂类来决定创建哪一个产品类的实例。

- 特点
    - 由工厂类来决定实例化哪个产品类，不暴露具体的产品创建过程。
    - 客户端不需要知道产品类的具体信息，减少了与产品类的耦合。
- 优缺点
    - 优点：客户端不需要关心对象的创建细节，降低了代码的耦合度。
    - 缺点：工厂类需要维护一个 `if` 或 `switch` 来判断创建哪种产品，如果产品种类增加，工厂类会变得非常庞大且难以维护。

**示例**：

```java
class Product {
    void use() {
        System.out.println("Using the product");
    }
}

class ConcreteProductA extends Product {
    @Override
    void use() {
        System.out.println("Using Product A");
    }
}

class ConcreteProductB extends Product {
    @Override
    void use() {
        System.out.println("Using Product B");
    }
}

class SimpleFactory {
    public Product createProduct(String type) {
        if (type.equals("A")) {
            return new ConcreteProductA();
        } else if (type.equals("B")) {
            return new ConcreteProductB();
        } else {
            return null;
        }
    }
}

public class Client {
    public static void main(String[] args) {
        SimpleFactory factory = new SimpleFactory();
        Product product = factory.createProduct("A");
        product.use();
    }
}
```

### 2. **工厂方法模式（Factory Method Pattern）**

工厂方法模式是工厂模式的核心。它通过定义一个接口来创建对象，由子类来决定实例化哪一个类。工厂方法模式将简单工厂中的创建产品的逻辑分散到了各个具体的工厂类中。

- 特点
    - 定义一个创建对象的接口，但让子类来决定具体实例化哪一个产品。
    - 通过继承和多态来解决简单工厂的缺点，避免了在一个类中维护大量的 `if` 或 `switch` 语句。
- 优缺点
    - 优点：符合开闭原则，增加新产品时只需要添加新的工厂类，不需要修改现有代码。
    - 缺点：增加了类的数量，系统更为复杂。

**示例**：

```java
interface Product {
    void use();
}

class ConcreteProductA implements Product {
    @Override
    public void use() {
        System.out.println("Using Product A");
    }
}

class ConcreteProductB implements Product {
    @Override
    public void use() {
        System.out.println("Using Product B");
    }
}

abstract class Creator {
    public abstract Product factoryMethod();
}

class ConcreteCreatorA extends Creator {
    @Override
    public Product factoryMethod() {
        return new ConcreteProductA();
    }
}

class ConcreteCreatorB extends Creator {
    @Override
    public Product factoryMethod() {
        return new ConcreteProductB();
    }
}

public class Client {
    public static void main(String[] args) {
        Creator creatorA = new ConcreteCreatorA();
        Product productA = creatorA.factoryMethod();
        productA.use();

        Creator creatorB = new ConcreteCreatorB();
        Product productB = creatorB.factoryMethod();
        productB.use();
    }
}
```

### 3. **抽象工厂模式（Abstract Factory Pattern）**

抽象工厂模式是工厂模式的进一步扩展，它提供了一个接口，用于创建一组相关或相互依赖的对象，而无需指定具体的类。与工厂方法模式不同，抽象工厂模式更侧重于一组产品的创建，而不是单个产品的创建。

- 特点
    - 提供一个接口，用来创建相关或依赖的多个产品。
    - 客户端通过抽象工厂来获取一系列的产品对象，而无需知道具体的实现。
- 优缺点
    - 优点：可以方便地更换产品系列（产品的族），符合开闭原则。
    - 缺点：增加了系统的复杂性，如果新增产品族或产品种类时需要修改现有的代码。

**示例**：

```java
interface ProductA {
    void useA();
}

interface ProductB {
    void useB();
}

class ConcreteProductA1 implements ProductA {
    @Override
    public void useA() {
        System.out.println("Using Product A1");
    }
}

class ConcreteProductB1 implements ProductB {
    @Override
    public void useB() {
        System.out.println("Using Product B1");
    }
}

class ConcreteProductA2 implements ProductA {
    @Override
    public void useA() {
        System.out.println("Using Product A2");
    }
}

class ConcreteProductB2 implements ProductB {
    @Override
    public void useB() {
        System.out.println("Using Product B2");
    }
}

interface AbstractFactory {
    ProductA createProductA();

    ProductB createProductB();
}

class ConcreteFactory1 implements AbstractFactory {
    @Override
    public ProductA createProductA() {
        return new ConcreteProductA1();
    }

    @Override
    public ProductB createProductB() {
        return new ConcreteProductB1();
    }
}

class ConcreteFactory2 implements AbstractFactory {
    @Override
    public ProductA createProductA() {
        return new ConcreteProductA2();
    }

    @Override
    public ProductB createProductB() {
        return new ConcreteProductB2();
    }
}

public class Client {
    public static void main(String[] args) {
        AbstractFactory factory1 = new ConcreteFactory1();
        ProductA productA1 = factory1.createProductA();
        ProductB productB1 = factory1.createProductB();
        productA1.useA();
        productB1.useB();

        AbstractFactory factory2 = new ConcreteFactory2();
        ProductA productA2 = factory2.createProductA();
        ProductB productB2 = factory2.createProductB();
        productA2.useA();
        productB2.useB();
    }
}
```

### 总结：

- **简单工厂模式**：由工厂类根据不同的条件决定创建不同的对象，适合产品种类少且变化不大时。
- **工厂方法模式**：通过子类来决定产品的创建，适合产品种类较多时，且产品可能会变化。
- **抽象工厂模式**：提供多个相关的产品的创建接口，适合需要创建一系列相关产品的场景。

## 观察者模式

观察者模式是一种行为设计模式，它允许一个对象（被观察者）在其状态发生变化时，自动通知所有依赖于它的对象（观察者），而不需要知道这些观察者的具体细节。其主要思想是实现“低耦合”，即对象之间的关系通过接口进行松散连接。为了避免使用过时的类，我们可以手动实现观察者模式。我们需要定义一个“观察者”接口和一个“被观察者”接口，并在被观察者中维护一个观察者的列表，通知观察者更新状态。

![image-20250131222844877](./images/设计模式/image-20250131222844877.png)

![image-20250131222858501](./images/设计模式/image-20250131222858501.png)

观察者模式在以下场景中非常适用：

- **事件驱动的系统**：如 GUI 事件处理、用户交互。
- **发布/订阅机制**：如新闻推送、社交媒体更新。
- **实时数据监控**：如股票、天气、系统监控等。
- **模型-视图-控制器（MVC）**：使视图根据模型的变化自动更新。
- **实时更新场景**：如游戏开发中的实时数据变化通知。

### 观察者

#### 观察者接口

```java
/**
 * 观察者接口
 */
public interface Observer {

    /**
     * 更新数据
     *
     * @param temperature 温度
     * @param humidity    湿度
     * @param pressure    气压
     */
    void update(float temperature, float humidity, float pressure);
}
```

#### 观察者的实现

```java
public class Observer1 implements Observer {

    /**
     * 更新数据
     *
     * @param temperature 温度
     * @param humidity    湿度
     * @param pressure    气压
     */
    @Override
    public void update(float temperature, float humidity, float pressure) {
        System.out.println("Observer1 显示数据：temperature = " + temperature + ";humidity = " + humidity);
    }
}

public class Observer2 implements Observer {

    /**
     * 更新数据
     *
     * @param temperature 温度
     * @param humidity    湿度
     * @param pressure    气压
     */
    @Override
    public void update(float temperature, float humidity, float pressure) {
        System.out.println("Observer2 显示数据：temperature = " + temperature + ";humidity = " + humidity);

    }
}

public class Observer3 implements Observer {

    /**
     * 更新数据
     *
     * @param temperature 温度
     * @param humidity    湿度
     * @param pressure    气压
     */
    @Override
    public void update(float temperature, float humidity, float pressure) {
        System.out.println("Observer3 显示数据：temperature = " + temperature + ";humidity = " + humidity);
    }
}
```

### 主题

#### 主体接口

```java
/**
 * 被观察者接口
 */
public interface Subject {
    void registerObserver(Observer observer);

    void removeObserver(Observer observer);

    void notifyObservers();
}
```

#### 主体实现

```java
import cn.bunny.pattern3.demo1.observer.Observer;

import java.util.ArrayList;
import java.util.List;

/**
 * 被观察者类
 */
public class WeatherStationSubject implements Subject {
    private final List<Observer> observers = new ArrayList<>();
    private float temperature;
    private float humidity;
    private float pressure;

    @Override
    public void registerObserver(Observer observer) {
        observers.add(observer);
    }

    @Override
    public void removeObserver(Observer observer) {
        observers.remove(observer);
    }

    @Override
    public void notifyObservers() {
        for (Observer observer : observers) {
            observer.update(temperature, humidity, pressure);
        }
    }

    public void setTemperature(float temperature, float humidity, float pressure) {
        this.temperature = temperature;
        this.humidity = humidity;
        this.pressure = pressure;
        notifyObservers();
    }
}
```

### 运行

```java
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) {
        WeatherStationSubject weatherStationSubject = new WeatherStationSubject();
        Observer observer1 = new Observer1();
        Observer observer2 = new Observer2();
        Observer observer3 = new Observer3();

        // 注册观察者
        weatherStationSubject.registerObserver(observer1);
        weatherStationSubject.registerObserver(observer2);
        weatherStationSubject.registerObserver(observer3);

        // 更新天气温度，观察者会收到通知
        weatherStationSubject.setTemperature(25.0f, 25.0f, 25.0f);
        weatherStationSubject.setTemperature(30.0f, 30.0f, 30.0f);

        // 移出观察者1
        weatherStationSubject.removeObserver(observer1);

        // 更新天气温度，观察者会收到通知
        System.out.println("--------------------------");
        weatherStationSubject.setTemperature(44.0f, 44.0f, 44.0f);
    }
}
```

![image-20250131223737965](./images/设计模式/image-20250131223737965.png)

## 装饰者模式

装饰器模式是一种结构型设计模式，允许在不修改对象代码的前提下，动态地给一个对象添加额外的功能。它通过“包装”原始对象，使用一个或多个装饰器类对其功能进行增强或修改。

简单来说，装饰器模式通过“装饰”原有对象来扩展功能，而不是通过继承来修改对象的行为。

适用的场景包括 I/O 流处理、GUI 组件、日志功能、权限管理、Web 请求处理等。在这些场景中，装饰器模式帮助程序员按需扩展功能，而不会破坏现有代码的结构。

**汽车案例**

假设你有一辆普通的车（**基本功能**），如果你想让这辆车变成运动型车或豪华车（**添加新功能**），你可以将这辆车包装在不同的装饰器中。例如：

- **基本车**：一辆普通的车。
- **运动型车**：在基本车上增加运动功能，比如加速性能、运动座椅等。
- **豪华车**：在基本车上增加奢华功能，如高档内饰、音响系统等。

通过使用装饰器模式，你可以自由组合这些功能（运动型 + 豪华型），而不需要修改原有的 `Car` 类。

![image-20250201105537485](./images/设计模式/image-20250201105537485.png)

**相机案例**

![image-20250201105612849](./images/设计模式/image-20250201105612849.png)

### 装饰器模式的结构

1. **Component（组件接口）**：定义了被装饰对象的共同行为，通常是一个接口或抽象类。
2. **ConcreteComponent（具体组件）**：实现了 `Component` 接口，表示被装饰的对象。
3. **Decorator（装饰器）**：实现 `Component` 接口，并持有一个 `Component` 对象，目的是对其进行包装。
4. **ConcreteDecorator（具体装饰器）**：扩展了 `Decorator` 类，为 `Component` 添加额外的功能。

#### 优点

1. **灵活性**：装饰器模式可以通过动态地组合多个装饰器来实现功能的拓展，而不需要修改现有类或创建大量的子类。
2. **遵循开放-封闭原则**：类对扩展开放，对修改封闭。你可以通过装饰器添加新功能，而无需修改现有的类代码。
3. **功能复用**：装饰器模式支持组合多个装饰器，通过不同的装饰器组合可以重用已有的功能。
4. **避免类膨胀**：与继承不同，装饰器模式避免了大量的子类创建，能够更灵活地对对象功能进行增强。

#### 缺点

1. **增加复杂性**：由于需要创建多个装饰器类，系统的结构可能变得更加复杂，维护和理解装饰器链条可能变得较为困难。
2. **多层装饰会导致性能开销**：装饰器模式通常会创建多个小对象进行嵌套包装，导致性能开销增加，尤其在装饰器链条很长时。
3. **难以管理装饰器的组合**：如果装饰器有依赖关系或需要特定的顺序才能正确工作，那么组合多个装饰器可能会变得更加困难，增加了使用的难度。

### 相机

#### 相机接口

```java
public interface Camera {

    /**
     * 操作
     */
    void operation();
}
```

#### 相机实现

```java
public class TakePhotoCamera implements Camera {
    /**
     * 操作
     */
    @Override
    public void operation() {
        System.out.println("拍照。。。");
    }
}

public abstract class CameraDecorator implements Camera {

    final Camera camera;

    public CameraDecorator(Camera camera) {
        this.camera = camera;
    }
}

public class FilterCameraDecorator extends CameraDecorator {
    public FilterCameraDecorator(Camera camera) {
        super(camera);
    }

    /**
     * 操作
     */
    @Override
    public void operation() {
        camera.operation();
        System.out.println("滤镜功能。。。");
    }
}
```

### 运行

```java
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();
    }
}
```

![image-20250201135138918](./images/设计模式/image-20250201135138918.png)

## 命令模式

