MultiThread/README/设计模式.md

738 lines
20 KiB
Markdown
Raw Normal View History

2025-01-31 19:13:14 +08:00
# 设计模式
## 单例模式
### 懒汉模式
#### 双重检查锁定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;
}
}
```
#### 适用场景
- 如果单例对象比较重,且只在程序中某些特定情况下才使用,懒汉模式可以带来性能优势。
- 在低并发环境或单线程环境下,懒汉模式使用较为简单,不会有多线程安全问题。
- 对于高并发且需要频繁访问单例的场景,推荐使用**静态内部类**或**饿汉模式**来避免懒汉模式可能带来的性能问题。
#### 总结
2025-01-31 22:54:45 +08:00
懒汉模式有时为了延迟初始化而牺牲了性能特别是在多线程环境下。为了保证线程安全可以采用双重检查锁定DCL或静态内部类的方式而**静态内部类方式是最推荐的方式**
,它避免了同步开销,同时也能确保线程安全。
2025-01-31 19:13:14 +08:00
- **优点**
2025-01-31 22:54:45 +08:00
1. 延迟加载,节省资源。
2. 内存优化,只有在需要时才实例化。
3. 减少不必要的初始化开销。
2025-01-31 19:13:14 +08:00
- **缺点**
2025-01-31 22:54:45 +08:00
1. 传统懒汉模式线程不安全(多个线程可能会创建多个实例)。
2. 使用同步机制会有性能开销,特别是在多线程环境下。
3. 代码复杂性较高,容易引入错误。
4. 不适合高并发场景,特别是频繁访问时会影响性能。
2025-01-31 19:13:14 +08:00
### 饿汉模式
2025-01-31 22:54:45 +08:00
**饿汉模式**Eager Initialization是单例模式的一种实现方式在该方式中单例实例在类加载时就已经创建完成而不是在首次使用时才创建。换句话说**饿汉模式**
的单例实例在类被加载时就会立即初始化,确保了单例模式的唯一性。
2025-01-31 19:13:14 +08:00
```java
public class Singleton {
// 在类加载时就初始化单例对象
private static final Singleton INSTANCE = new Singleton();
// 私有构造函数,防止外部通过 new 创建实例
private Singleton() {
}
// 提供全局访问点
public static Singleton getInstance() {
return INSTANCE;
}
}
```
#### 适用场景
- **简单应用**:适合没有延迟初始化需求的小型应用,或者单例对象的创建非常轻量,不会影响系统性能的场景。
- **实例化不耗费太多资源**:如果单例对象的初始化过程非常轻量级且无须延迟初始化,可以使用饿汉模式。
- **类加载顺序固定**:如果不在乎单例对象在启动时是否初始化,且单例对象的初始化过程没有严重性能损失,可以选择饿汉模式。
#### 总结
- **优点**:简单、线程安全、性能高(没有锁机制)、实现方便。
- **缺点**:不支持延迟加载、可能会浪费资源(如果单例对象不常用时)。
饿汉模式是单例模式中最简单的实现方式,适用于大多数情况下单例对象的创建开销较小,且不需要延迟初始化的场景。如果单例对象的创建非常轻量且不依赖于后期加载时的资源,饿汉模式是一个不错的选择。
### 枚举类型实现
2025-01-31 22:54:45 +08:00
**枚举类型实现单例模式**Enum Singleton是实现单例模式的另一种方式优点是更加简洁、可靠并且避免了许多常见的单例实现方式如懒汉模式和饿汉模式可能出现的问题。使用枚举类型的单例实现方式自
**Java 5** 引入以来,已经成为了最推荐的单例模式实现方式之一。
2025-01-31 19:13:14 +08:00
**当你不需要懒加载或延迟初始化时,使用枚举实现单例模式是最理想的选择。**
```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**
简单工厂模式是工厂模式的一种简单形式,**它并不属于设计模式中的结构**,它是通过一个工厂类来决定创建哪一个产品类的实例。
- 特点
2025-01-31 22:54:45 +08:00
- 由工厂类来决定实例化哪个产品类,不暴露具体的产品创建过程。
- 客户端不需要知道产品类的具体信息,减少了与产品类的耦合。
2025-01-31 19:13:14 +08:00
- 优缺点
2025-01-31 22:54:45 +08:00
- 优点:客户端不需要关心对象的创建细节,降低了代码的耦合度。
- 缺点:工厂类需要维护一个 `if``switch` 来判断创建哪种产品,如果产品种类增加,工厂类会变得非常庞大且难以维护。
2025-01-31 19:13:14 +08:00
**示例**
```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**
工厂方法模式是工厂模式的核心。它通过定义一个接口来创建对象,由子类来决定实例化哪一个类。工厂方法模式将简单工厂中的创建产品的逻辑分散到了各个具体的工厂类中。
- 特点
2025-01-31 22:54:45 +08:00
- 定义一个创建对象的接口,但让子类来决定具体实例化哪一个产品。
- 通过继承和多态来解决简单工厂的缺点,避免了在一个类中维护大量的 `if``switch` 语句。
2025-01-31 19:13:14 +08:00
- 优缺点
2025-01-31 22:54:45 +08:00
- 优点:符合开闭原则,增加新产品时只需要添加新的工厂类,不需要修改现有代码。
- 缺点:增加了类的数量,系统更为复杂。
2025-01-31 19:13:14 +08:00
**示例**
```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();
2025-01-31 22:54:45 +08:00
2025-01-31 19:13:14 +08:00
Creator creatorB = new ConcreteCreatorB();
Product productB = creatorB.factoryMethod();
productB.use();
}
}
```
### 3. **抽象工厂模式Abstract Factory Pattern**
抽象工厂模式是工厂模式的进一步扩展,它提供了一个接口,用于创建一组相关或相互依赖的对象,而无需指定具体的类。与工厂方法模式不同,抽象工厂模式更侧重于一组产品的创建,而不是单个产品的创建。
- 特点
2025-01-31 22:54:45 +08:00
- 提供一个接口,用来创建相关或依赖的多个产品。
- 客户端通过抽象工厂来获取一系列的产品对象,而无需知道具体的实现。
2025-01-31 19:13:14 +08:00
- 优缺点
2025-01-31 22:54:45 +08:00
- 优点:可以方便地更换产品系列(产品的族),符合开闭原则。
- 缺点:增加了系统的复杂性,如果新增产品族或产品种类时需要修改现有的代码。
2025-01-31 19:13:14 +08:00
**示例**
```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();
2025-01-31 22:54:45 +08:00
2025-01-31 19:13:14 +08:00
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();
2025-01-31 22:54:45 +08:00
2025-01-31 19:13:14 +08:00
AbstractFactory factory2 = new ConcreteFactory2();
ProductA productA2 = factory2.createProductA();
ProductB productB2 = factory2.createProductB();
productA2.useA();
productB2.useB();
}
}
```
### 总结:
- **简单工厂模式**:由工厂类根据不同的条件决定创建不同的对象,适合产品种类少且变化不大时。
- **工厂方法模式**:通过子类来决定产品的创建,适合产品种类较多时,且产品可能会变化。
2025-01-31 22:54:45 +08:00
- **抽象工厂模式**:提供多个相关的产品的创建接口,适合需要创建一系列相关产品的场景。
## 策略模式
![image-20250131223259043](./images/设计模式/image-20250131223259043.png)
![image-20250131223315954](./images/设计模式/image-20250131223315954.png)
我们通过策略模式来实现鸭子的飞行和叫声行为,使得它们可以在运行时灵活替换。
### 飞行行为
#### 飞行接口
```java
public interface FlyBehavior {
/**
* 飞的样子
*/
void fly();
}
```
#### 飞行实现
```java
public class FlyNoWay implements FlyBehavior {
/**
* 飞的样子
*/
@Override
public void fly() {
System.out.println("不能飞。。。");
}
}
public class FlyWithWings implements FlyBehavior {
/**
* 飞的样子
*/
@Override
public void fly() {
System.out.println("可以飞。。。");
}
}
```
### 叫的行为
#### 叫的接口
```java
public interface QuackBehavior {
/**
* 怎么叫的
*/
void quack();
}
```
#### 叫的实现
```java
public class MuteQuack implements QuackBehavior {
/**
* 怎么叫的
*/
@Override
public void quack() {
System.out.println("不会叫...");
}
}
public class Quack implements QuackBehavior {
/**
* 怎么叫的
*/
@Override
public void quack() {
System.out.println("鸭子叫。。。");
}
}
```
### 鸭子
```java
@Setter
public abstract class AbstractDuck {
// 设置新的叫声行为
QuackBehavior quackBehavior;
// 设置新的飞行行为
FlyBehavior flyBehavior;
public AbstractDuck() {
}
/**
* 展示什么类型的鸭子
*/
public abstract void display();
public void performFly() {
flyBehavior.fly();
}
public void performQuack() {
quackBehavior.quack();
}
public void swim() {
System.out.println("鸭子游泳");
}
}
```
#### 鸭子继承
```java
public class ModelDuck extends AbstractDuck {
private final String modelDuck = "橡皮🦆";
public ModelDuck() {
super.setFlyBehavior(new FlyNoWay());
super.quackBehavior = new MuteQuack();
}
/**
* 展示什么类型的鸭子
*/
@Override
public void display() {
System.out.println(modelDuck + "...");
}
/**
*
*/
@Override
public void swim() {
System.out.println(modelDuck + "不会游泳。。。");
}
}
public class WoodDuck extends AbstractDuck {
private final String modelDuck = "木头🦆";
public WoodDuck() {
super.flyBehavior = new FlyNoWay();
super.quackBehavior = new MuteQuack();
}
/**
* 展示什么类型的鸭子
*/
@Override
public void display() {
System.out.println(modelDuck + "...");
}
}
```
### 运行
```java
public class Main {
public static void main(String[] args) {
ModelDuck modelDuck = new ModelDuck();
modelDuck.display();
modelDuck.performFly();
modelDuck.performQuack();
modelDuck.swim();
System.out.println("--------------------------------");
AbstractDuck woodDuck = new WoodDuck();
woodDuck.display();
woodDuck.performFly();
woodDuck.performQuack();
woodDuck.swim();
}
}
```
![image-20250131224206984](./images/设计模式/image-20250131224206984.png)
## 观察者模式
观察者模式是一种行为设计模式,它允许一个对象(被观察者)在其状态发生变化时,自动通知所有依赖于它的对象(观察者),而不需要知道这些观察者的具体细节。其主要思想是实现“低耦合”,即对象之间的关系通过接口进行松散连接。
![image-20250131222844877](./images/设计模式/image-20250131222844877.png)
![image-20250131222858501](./images/设计模式/image-20250131222858501.png)
为了避免使用过时的类,我们可以手动实现观察者模式。我们需要定义一个“观察者”接口和一个“被观察者”接口,并在被观察者中维护一个观察者的列表,通知观察者更新状态。
### 观察者
#### 观察者接口
```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.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.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;
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)
## 装饰者模式