创建型设计模式详解

121 阅读14分钟

创建型设计模式提供了创建对象的机制, 能够提升已有代码的灵活性和可复用性。

工厂模式

简单工厂模式

定义:通过一个工厂类,根据传入的参数动态决定创建哪种具体产品类的实例。

适用场景:产品种类较少且变化不频繁的场景。

结构

classDiagram
    class Product {
        <<interface>>
        +use()
    }
    class ConcreteProductA {
        +use()
    }
    class ConcreteProductB {
        +use()
    }
    class SimpleFactory {
        +createProduct(String type): Product
    }
    SimpleFactory --> Product : 创建
    Product <|.. ConcreteProductA : 实现
    Product <|.. ConcreteProductB : 实现

代码示例

// 抽象产品接口
interface Product {
    void use();
}

// 具体产品A
class ConcreteProductA implements Product {
    @Override
    public void use() {
        System.out.println("使用产品A");
    }
}

// 具体产品B
class ConcreteProductB implements Product {
    @Override
    public void use() {
        System.out.println("使用产品B");
    }
}

// 简单工厂类
class SimpleFactory {
    public Product createProduct(String type) {
        if ("A".equals(type)) {
            return new ConcreteProductA();
        } else if ("B".equals(type)) {
            return new ConcreteProductB();
        }
        throw new IllegalArgumentException("未知产品类型");
    }
}

// 客户端
public class Client {
    public static void main(String[] args) {
        SimpleFactory factory = new SimpleFactory();
        Product productA = factory.createProduct("A");
        productA.use(); // 输出:使用产品A
    }
}

工厂方法模式

定义:定义一个创建对象的接口,但由子类决定实例化哪个类。将对象的创建延迟到子类。

适用场景:需要支持多种产品类型且可能频繁扩展的场景。

结构

classDiagram
    class Product {
        <<interface>>
        +use()
    }
    class ConcreteProductA {
        +use()
    }
    class ConcreteProductB {
        +use()
    }
    class Factory {
        <<abstract>>
        +createProduct(): Product
    }
    class ConcreteFactoryA {
        +createProduct(): Product
    }
    class ConcreteFactoryB {
        +createProduct(): Product
    }
    Factory <|-- ConcreteFactoryA : 继承
    Factory <|-- ConcreteFactoryB : 继承
    ConcreteFactoryA --> ConcreteProductA : 创建
    ConcreteFactoryB --> ConcreteProductB : 创建
    Product <|.. ConcreteProductA : 实现
    Product <|.. ConcreteProductB : 实现

代码示例

// 抽象产品接口
interface Product {
    void use();
}

// 具体产品A
class ConcreteProductA implements Product {
    @Override
    public void use() {
        System.out.println("使用产品A");
    }
}

// 具体产品B
class ConcreteProductB implements Product {
    @Override
    public void use() {
        System.out.println("使用产品B");
    }
}

// 抽象工厂接口
interface Factory {
    Product createProduct();
}

// 具体工厂A
class ConcreteFactoryA implements Factory {
    @Override
    public Product createProduct() {
        return new ConcreteProductA();
    }
}

// 具体工厂B
class ConcreteFactoryB implements Factory {
    @Override
    public Product createProduct() {
        return new ConcreteProductB();
    }
}

// 客户端
public class Client {
    public static void main(String[] args) {
        Factory factoryA = new ConcreteFactoryA();
        Product productA = factoryA.createProduct();
        productA.use(); // 输出:使用产品A

        Factory factoryB = new ConcreteFactoryB();
        Product productB = factoryB.createProduct();
        productB.use(); // 输出:使用产品B
    }
}

抽象工厂模式

定义:提供一个接口,用于创建相关或依赖对象的家族,而无需指定具体类。

适用场景:需要创建一组相关或依赖对象的场景(如跨平台UI组件库)。

结构

classDiagram
    class AbstractFactory {
        <<interface>>
        +createButton(): Button
        +createTextField(): TextField
    }

    class WindowsFactory {
        +createButton(): WindowsButton
        +createTextField(): WindowsTextField
    }

    class MacFactory {
        +createButton(): MacButton
        +createTextField(): MacTextField
    }

    class Button {
        <<interface>>
        +render()
    }

    class WindowsButton {
        +render()
    }

    class MacButton {
        +render()
    }

    class TextField {
        <<interface>>
        +display()
    }

    class WindowsTextField {
        +display()
    }

    class MacTextField {
        +display()
    }

    AbstractFactory <|.. WindowsFactory : 实现
    AbstractFactory <|.. MacFactory : 实现
    Button <|.. WindowsButton : 实现
    Button <|.. MacButton : 实现
    TextField <|.. WindowsTextField : 实现
    TextField <|.. MacTextField : 实现
    WindowsFactory --> WindowsButton : 创建
    WindowsFactory --> WindowsTextField : 创建
    MacFactory --> MacButton : 创建
    MacFactory --> MacTextField : 创建

代码示例

// 抽象产品族A
interface Button {
    void render();
}

// 具体产品A1:Windows按钮
class WindowsButton implements Button {
    @Override
    public void render() {
        System.out.println("渲染Windows风格按钮");
    }
}

// 具体产品A2:Mac按钮
class MacButton implements Button {
    @Override
    public void render() {
        System.out.println("渲染Mac风格按钮");
    }
}

// 抽象产品族B
interface TextField {
    void display();
}

// 具体产品B1:Windows文本框
class WindowsTextField implements TextField {
    @Override
    public void display() {
        System.out.println("显示Windows风格文本框");
    }
}

// 具体产品B2:Mac文本框
class MacTextField implements TextField {
    @Override
    public void display() {
        System.out.println("显示Mac风格文本框");
    }
}

// 抽象工厂接口
interface GUIFactory {
    Button createButton();
    TextField createTextField();
}

// 具体工厂1:Windows工厂
class WindowsFactory implements GUIFactory {
    @Override
    public Button createButton() {
        return new WindowsButton();
    }

    @Override
    public TextField createTextField() {
        return new WindowsTextField();
    }
}

// 具体工厂2:Mac工厂
class MacFactory implements GUIFactory {
    @Override
    public Button createButton() {
        return new MacButton();
    }

    @Override
    public TextField createTextField() {
        return new MacTextField();
    }
}

// 客户端
public class Client {
    public static void main(String[] args) {
        GUIFactory windowsFactory = new WindowsFactory();
        Button winButton = windowsFactory.createButton();
        TextField winTextField = windowsFactory.createTextField();
        winButton.render();      // 输出:渲染Windows风格按钮
        winTextField.display();  // 输出:显示Windows风格文本框

        GUIFactory macFactory = new MacFactory();
        Button macButton = macFactory.createButton();
        TextField macTextField = macFactory.createTextField();
        macButton.render();      // 输出:渲染Mac风格按钮
        macTextField.display();  // 输出:显示Mac风格文本框
    }
}

工厂模式对比

模式核心特点扩展性适用场景
简单工厂单工厂类,通过参数创建不同产品差(需修改工厂类)产品类型少且不频繁变化
工厂方法每个产品对应一个工厂子类好(新增子类即可)需要灵活扩展产品类型的场景
抽象工厂生产多个相关产品组成的家族中等(产品族难扩展)需要保证产品兼容性的复杂系统

生成器设计模式

模式定义

生成器模式是一种创建型设计模式,用于分步骤构建复杂对象。它通过将对象的构建过程与其表示分离,使得相同的构建过程可以创建不同的对象表示。该模式特别适用于需要多个配置参数或构建步骤的对象,避免了冗长的构造函数参数列表(称为“重叠构造函数”问题),并提高了代码的可读性和灵活性。

核心角色

生成器模式包含以下关键角色:

角色说明
产品(Product)最终要构建的复杂对象,包含多个组成部分(如电脑的 CPU、内存、硬盘)。
生成器(Builder)定义构建产品各部分的抽象接口(如 setCPU()setRAM())。
具体生成器(Concrete Builder)实现生成器接口,提供构建各部分的具体逻辑,并返回最终产品。
指挥者(Director)可选角色,负责调用生成器的步骤方法,控制构建流程(如组装电脑的标准流程)。

结构

classDiagram
    class Product {
        -cpu: String
        -ram: String
        -storage: String
        +toString(): String
    }

    class Builder {
        <<interface>>
        +buildCPU(String cpu): void
        +buildRAM(String ram): void
        +buildStorage(String storage): void
        +getResult(): Product
    }

    class ComputerBuilder {
        -product: Product
        +buildCPU(String cpu): void
        +buildRAM(String ram): void
        +buildStorage(String storage): void
        +getResult(): Product
    }

    class Director {
        -builder: Builder
        +construct(): void
    }

    Product <-- ComputerBuilder : 创建
    Builder <|.. ComputerBuilder : 实现
    Director --> Builder : 使用

代码示例

以“组装电脑”为例,演示生成器模式的应用:

// 步骤1:定义产品类(Computer)
public class Computer {
    private String cpu;
    private String ram;
    private String storage;

    public void setCpu(String cpu) { this.cpu = cpu; }
    public void setRam(String ram) { this.ram = ram; }
    public void setStorage(String storage) { this.storage = storage; }

    @Override
    public String toString() {
        return "Computer [CPU=" + cpu + ", RAM=" + ram + ", Storage=" + storage + "]";
    }
}

// 步骤2:定义生成器接口(ComputerBuilder)
public interface ComputerBuilder {
    void buildCPU(String cpu);
    void buildRAM(String ram);
    void buildStorage(String storage);
    Computer getResult();
}

// 步骤3:实现具体生成器(StandardComputerBuilder)
public class StandardComputerBuilder implements ComputerBuilder {
    private Computer computer = new Computer();

    @Override
    public void buildCPU(String cpu) {
        computer.setCpu(cpu);
    }

    @Override
    public void buildRAM(String ram) {
        computer.setRam(ram);
    }

    @Override
    public void buildStorage(String storage) {
        computer.setStorage(storage);
    }

    @Override
    public Computer getResult() {
        return computer;
    }
}

// 步骤4:定义指挥者(Director,可选)
public class Director {
    private ComputerBuilder builder;

    public Director(ComputerBuilder builder) {
        this.builder = builder;
    }

    // 定义标准组装流程
    public void constructBasicComputer() {
        builder.buildCPU("Intel i5");
        builder.buildRAM("8GB DDR4");
        builder.buildStorage("512GB SSD");
    }

    public void constructHighEndComputer() {
        builder.buildCPU("AMD Ryzen 9");
        builder.buildRAM("32GB DDR5");
        builder.buildStorage("2TB NVMe SSD");
    }
}

// 步骤5:客户端使用
public class Client {
    public static void main(String[] args) {
        // 创建生成器
        ComputerBuilder builder = new StandardComputerBuilder();
        
        // 使用指挥者(可选)
        Director director = new Director(builder);
        director.constructBasicComputer();
        
        // 直接通过生成器构建(无指挥者)
        // builder.buildCPU("Intel i5");
        // builder.buildRAM("8GB DDR4");
        // builder.buildStorage("512GB SSD");
        
        // 获取最终产品
        Computer computer = builder.getResult();
        System.out.println(computer);  // 输出:Computer [CPU=Intel i5, RAM=8GB DDR4, Storage=512GB SSD]
    }
}

生成器模式的变体:链式生成器(Fluent Builder)

通过返回 this 实现链式调用,提升代码可读性:

public class Computer {
    private String cpu;
    private String ram;
    private String storage;

    private Computer(Builder builder) {
        this.cpu = builder.cpu;
        this.ram = builder.ram;
        this.storage = builder.storage;
    }

    public static class Builder {
        private String cpu;
        private String ram;
        private String storage;

        public Builder cpu(String cpu) {
            this.cpu = cpu;
            return this;
        }

        public Builder ram(String ram) {
            this.ram = ram;
            return this;
        }

        public Builder storage(String storage) {
            this.storage = storage;
            return this;
        }

        public Computer build() {
            return new Computer(this);
        }
    }
}

// 使用方式
Computer computer = new Computer.Builder()
    .cpu("Intel i7")
    .ram("16GB DDR4")
    .storage("1TB NVMe SSD")
    .build();

应用场景

生成器模式适用于以下场景:

  • 多参数对象构建:对象需要多个可选参数(如订单、用户配置)。
  • 复杂构建流程:对象构建涉及多个步骤(如生成PDF报告需设置页眉、正文、页脚)。
  • 避免重叠构造函数:替代多个重载的构造函数(如 new User(name, age, email, phone))。
  • 构建不可变对象:通过生成器逐步设置参数后,返回不可变对象(如Java中的StringBuilder生成String)。

优缺点分析

优点缺点
解耦构建过程与产品表示增加代码复杂度(需定义生成器类)
支持分步骤构建和灵活配置对简单对象可能过度设计
提高代码可读性和可维护性

生成器模式 vs 工厂模式

维度生成器模式工厂模式
核心目标分步骤构建复杂对象创建单一对象
适用场景多参数、多步骤的对象构建直接创建完整对象
代码复杂度高(需定义生成器类)低(直接调用工厂方法)
典型应用StringBuilder、文档生成器Calendar.getInstance()、Spring Bean

总结

生成器模式通过将复杂对象的构建过程分解为独立的步骤,提供了高度灵活性和可维护性。其核心价值在于:

  • 代码清晰:避免冗长的构造函数参数列表。

  • 灵活扩展:支持逐步构建和不同产品表示。

  • 解耦构建逻辑:分离构建过程与产品实现。

适用建议:

  • 当对象需要多个可选参数或构建步骤时,优先选择生成器模式。

  • 对于简单对象,直接使用构造函数或工厂方法即可。

原型模式

定义

原型模式(Prototype Pattern)  是一种创建型设计模式,通过复制现有对象(原型)来创建新对象,而无需依赖子类或构造方法。其核心思想是以现有实例为模板,通过克隆机制生成新对象,适用于对象创建成本高需动态配置对象的场景。


核心思想

  • 克隆代替构造:避免重复初始化复杂对象,直接基于已有对象复制生成新实例。
  • 动态扩展:允许运行时动态添加或修改对象的属性。
  • 性能优化:减少资源消耗(如数据库查询、复杂计算)。

模式结构

角色说明
原型接口(Prototype)定义克隆方法(如 clone()),通常实现 Cloneable 接口(Java)。
具体原型类(ConcretePrototype)实现克隆方法的具体类,决定浅拷贝或深拷贝。
客户端(Client)通过调用原型对象的克隆方法创建新对象。
classDiagram
    class Prototype {
        <<interface>>
        +clone(): Prototype
    }

    class ConcretePrototype {
        -field1: String
        -field2: Integer
        +clone(): Prototype
        +setField1(String)
        +getField1(): String
    }

    class Client {
        -prototype: Prototype
        +operation()
    }

    Prototype <|.. ConcretePrototype : 实现
    Client --> Prototype : 使用

代码示例

以“图形编辑器”为例,实现圆形(Circle)和矩形(Rectangle)的原型克隆:

// 1. 原型接口(实现 Cloneable)
interface Shape extends Cloneable {
    Shape clone();
    void draw();
}

// 2. 具体原型类:圆形
class Circle implements Shape {
    private String color;
    private int radius;

    public Circle(String color, int radius) {
        this.color = color;
        this.radius = radius;
    }

    @Override
    public Shape clone() {
        try {
            return (Circle) super.clone();  // 浅拷贝(引用类型需手动处理)
        } catch (CloneNotSupportedException e) {
            return null;
        }
    }

    @Override
    public void draw() {
        System.out.println("绘制圆形:颜色=" + color + ", 半径=" + radius);
    }

    public void setColor(String color) {
        this.color = color;
    }
}

// 3. 具体原型类:矩形(深拷贝示例)
class Rectangle implements Shape {
    private String color;
    private int width;
    private int height;
    private Dimensions dimensions;  // 引用类型字段

    public Rectangle(String color, int width, int height, Dimensions dimensions) {
        this.color = color;
        this.width = width;
        this.height = height;
        this.dimensions = dimensions;
    }

    @Override
    public Shape clone() {
        // 深拷贝:手动复制引用类型字段
        Rectangle cloned = new Rectangle(color, width, height, dimensions.clone());
        return cloned;
    }

    @Override
    public void draw() {
        System.out.println("绘制矩形:颜色=" + color + ", 尺寸=" + width + "x" + height 
            + ", 单位=" + dimensions.getUnit());
    }
}

// 引用类型辅助类(需实现克隆)
class Dimensions implements Cloneable {
    private String unit;

    public Dimensions(String unit) {
        this.unit = unit;
    }

    public String getUnit() {
        return unit;
    }

    @Override
    public Dimensions clone() {
        try {
            return (Dimensions) super.clone();  // 浅拷贝(若嵌套对象需递归处理)
        } catch (CloneNotSupportedException e) {
            return null;
        }
    }
}

// 4. 客户端使用
public class Client {
    public static void main(String[] args) {
        // 创建原型对象
        Shape redCircle = new Circle("红色", 10);
        Shape blueRectangle = new Rectangle("蓝色", 20, 30, new Dimensions("厘米"));

        // 克隆对象并修改属性
        Shape clonedCircle = redCircle.clone();
        ((Circle) clonedCircle).setColor("绿色");

        Shape clonedRectangle = blueRectangle.clone();

        // 绘制图形
        redCircle.draw();       // 输出:绘制圆形:颜色=红色, 半径=10
        clonedCircle.draw();    // 输出:绘制圆形:颜色=绿色, 半径=10
        clonedRectangle.draw(); // 输出:绘制矩形:颜色=蓝色, 尺寸=20x30, 单位=厘米
    }
}

应用场景

复杂对象初始化:对象创建需大量资源(如数据库连接、文件IO),通过克隆复用已有实例。

动态配置对象:运行时根据用户配置生成不同变体的对象(如游戏中的角色属性模板)。

撤销/重做功能:保存对象历史状态快照(如文档编辑器的撤销栈)。

优缺点

优点缺点
避免重复初始化复杂对象深拷贝实现复杂(需递归处理)
动态生成对象变体需注意循环引用的处理
提升性能(减少资源消耗)可能破坏封装性(访问私有字段)

与其他模式对比

模式核心区别
工厂模式通过子类创建对象,原型模式直接复制现有对象。
单例模式单例限制实例数量,原型模式生成多个克隆。
备忘录模式备忘录保存状态,原型复制整个对象。

最佳实践

优先使用深拷贝:避免引用共享导致意外修改(如 Rectangle 中的 Dimensions 字段)。

实现标记接口:Java 中通过 Cloneable 接口标识可克隆对象,但需手动实现 clone()

结合工厂模式:使用原型管理器(注册表)存储常用原型,按需克隆。

实际案例

Java 的 Object.clone():基础克隆机制,需结合 Cloneable 接口使用。

Spring 的 Bean 作用域:原型作用域的 Bean 每次请求生成新实例(通过克隆配置好的原型 Bean)。

游戏开发中的敌人生成:克隆预配置的敌人模板,动态调整属性(如血量、攻击力)。

总结

原型模式通过克隆机制高效生成对象,尤其适用于复杂对象初始化动态配置场景。其核心在于合理选择浅拷贝深拷贝,并确保克隆过程不破坏对象完整性。结合工厂模式或注册表管理,可进一步提升系统的灵活性和可维护性。

单例模式详解

1. 定义

单例模式(Singleton Pattern)是一种创建型设计模式,确保一个类只有一个实例,并提供一个全局访问点。它常用于管理共享资源(如配置、日志记录器、数据库连接池),避免重复创建对象带来的开销或不一致性。

2. 核心思想

  • 唯一性:类只能有一个实例。
  • 全局访问:通过静态方法提供全局访问入口。
  • 延迟初始化(可选):实例在第一次使用时创建,而非类加载时。

3. 类图(Mermaid)

classDiagram
    class Singleton {
        -static instance: Singleton
        -Singleton()  // 私有构造方法
        +static getInstance(): Singleton
        +someBusinessMethod() void
    }

说明

  • 私有构造方法:禁止外部通过 new 创建实例。
  • 静态实例变量:保存唯一实例。
  • 静态方法 getInstance() :全局访问入口。

4. 常见实现方式

4.1 饿汉式(Eager Initialization)

特点:类加载时立即初始化实例,线程安全但可能浪费资源。

public class EagerSingleton {
    // 类加载时直接初始化实例
    private static final EagerSingleton instance = new EagerSingleton();
    
    // 私有构造方法
    private EagerSingleton() {}
    
    // 全局访问点
    public static EagerSingleton getInstance() {
        return instance;
    }
}

优点:实现简单,线程安全。
缺点:实例提前创建,若未使用则浪费内存。


4.2 懒汉式(Lazy Initialization)

特点:延迟实例化,但需解决线程安全问题。

4.2.1 非线程安全版
public class LazySingleton {
    private static LazySingleton instance;
    
    private LazySingleton() {}
    
    // 非线程安全:多线程可能创建多个实例
    public static LazySingleton getInstance() {
        if (instance == null) {
            instance = new LazySingleton();
        }
        return instance;
    }
}
4.2.2 线程安全版(同步方法)
public class ThreadSafeLazySingleton {
    private static ThreadSafeLazySingleton instance;
    
    private ThreadSafeLazySingleton() {}
    
    // 同步方法保证线程安全,但性能较低
    public static synchronized ThreadSafeLazySingleton getInstance() {
        if (instance == null) {
            instance = new ThreadSafeLazySingleton();
        }
        return instance;
    }
}

缺点:同步锁导致性能下降。

4.3 双重检查锁(Double-Checked Locking)

特点:减少同步代码块,兼顾线程安全与性能。

public class DCLSingleton {
    // volatile 防止指令重排序
    private static volatile DCLSingleton instance;
    
    private DCLSingleton() {}
    
    public static DCLSingleton getInstance() {
        if (instance == null) {                  // 第一次检查
            synchronized (DCLSingleton.class) {  // 加锁
                if (instance == null) {           // 第二次检查
                    instance = new DCLSingleton();
                }
            }
        }
        return instance;
    }
}

优点:线程安全且性能较高。
关键点volatile 防止 JVM 指令重排序导致的未完全初始化问题。

4.4 静态内部类(Static Inner Class)

特点:利用类加载机制保证线程安全,且延迟初始化。

public class InnerClassSingleton {
    private InnerClassSingleton() {}
    
    // 静态内部类持有实例
    private static class SingletonHolder {
        private static final InnerClassSingleton INSTANCE = new InnerClassSingleton();
    }
    
    public static InnerClassSingleton getInstance() {
        return SingletonHolder.INSTANCE;
    }
}

原理:内部类 SingletonHolder 在首次调用 getInstance() 时加载,实现延迟初始化且线程安全。

4.5 枚举(Enum)

特点:简洁、线程安全,且天然防止反射和序列化破坏单例。

public enum EnumSingleton {
    INSTANCE;  // 单例实例
    
    public void someMethod() {
        // 业务逻辑
    }
}

// 使用示例
EnumSingleton instance = EnumSingleton.INSTANCE;

优点

  • 无需考虑反射攻击(枚举类无法通过反射创建实例)。
  • 序列化自动处理,不会生成新对象。

5. 防止破坏单例

5.1 反射攻击

通过反射调用私有构造方法可破坏单例。
防御方法:在构造方法中抛出异常。

private Singleton() {
    if (instance != null) {
        throw new RuntimeException("禁止反射创建实例!");
    }
}

5.2 序列化攻击

反序列化可能生成新实例。
防御方法:实现 readResolve() 方法。

protected Object readResolve() {
    return getInstance();
}

6. 应用场景

  1. 配置管理:全局唯一的配置对象。
  2. 日志记录器:统一管理日志输出。
  3. 数据库连接池:避免频繁创建连接。
  4. 缓存系统:统一管理缓存数据。

7. 总结

实现方式线程安全延迟初始化防反射防序列化
饿汉式✔️
懒汉式(同步方法)✔️✔️
双重检查锁✔️✔️
静态内部类✔️✔️
枚举✔️✔️✔️

推荐选择

  • 简单场景 → 饿汉式
  • 高并发场景 → 双重检查锁 或 静态内部类
  • 绝对安全场景 → 枚举

单例模式通过严格控制实例数量,确保全局一致性,是管理共享资源的首选方案。

后续内容更新中,请耐心等待