创建型模式

1.单例模式:

是java中最简单模式之一

特点:单例类只能有一个实例

           单例类必须自己创建自己的唯一实例

           单例类必须给所有其他对象提供这一实例

(1)饿汉式(比较常用,但容易产生垃圾对象):

优点:没有加锁,执行效率会提高,线程安全,获取实例速度快(提前创建好了,类加载时就创建实例)

缺点:类加载时就初始化,不能延迟加载,浪费内存

适用于:单例对象较小,对内存要求不高的场景

//静态代码块:只执行一次
//线程安全  浪费资源
public class Eager1 {
    private Eager1(){ }
    private static Eager1 instance;//实例

    public static Eager1 getInstance() {//访问点,只能通过getInstance这个方法访问
        return instance;
    }

    //利用静态代码块的特点来完成单例的创建
    static{
        instance=new Eager1();
    }
}
//常量
public class Eager2 {
    private static final Eager2 instance=new Eager2();//final
    private Eager2(){}
    public static Eager2 getInstance()//访问点
    {
        return instance;
    }
}

(2)懒汉式:

是一种延迟初始化的实现方式,只有在第一次使用时才会创建实例。

基础懒汉式:

优点:延迟初始化,第一次调用的时候才创建实例,避免了不必要的资源占用,灵活控制初始化时机,可以在运行时决定是否初始化

缺点:在多线程环境下可能创建多个实例,破坏单例原则

适用场景:适合初始化成本高的对象(数据库连接池、线程池等)

非线程安全:

public class Singleton {
    private static Singleton instance;
    
    private Singleton() {}  // 私有构造
    
    public static Singleton getInstance() {
        if (instance == null) {          // 第一次调用时创建
            instance = new Singleton();  // 非线程安全!
        }
        return instance;
    }
}

线程安全改进,加锁:

public class Singleton {
    private static Singleton instance;
    
    private Singleton() {}
    
    public static synchronized Singleton getInstance() {//synchronized 加锁
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

(3)双重检查锁

        结合延迟加载和线程安全,减少同步锁的开销

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;
    }
}

volaile 关键字禁止指令重排序,避免返回未初始化的实例。两次检查确保线程安全。

优点:线程安全且性能较高

缺点:代码较复杂,需理解内存模型

适合场景:高并发环境

(4)静态内部类

        利用类加载机制保证线程安全,同时延迟加载

public class Singleton {
    private Singleton() {}
    
    private static class Holder {
        private static final Singleton instance = new Singleton();
    }
    
    public static Singleton getInstance() {
        return Holder.instance;
    }
}

原理:内部类holder在getinstance()首次调用时才会加载

优点:线程安全、延迟加载、无锁高性能

缺点:无法防止反射攻击

适用场景:大多数场景

(5)枚举

基于枚举类型的天然单例特性,防止反射和序列化破坏

public enum Singleton {
    INSTANCE;
    
    public void doSomething() {
        // 业务方法
    }
}

优点:线程安全,天然防止反射创建新实例,自动处理序列化和反序列化

缺点:不够灵活(无法继承其他类)

适用场景:需要绝对防止多实例的场景(如配置管理器)

2.原型模式

通过复制现有对象(原型)来创建新对象,而不是通过new关键字实例化。这种方式特别适用于创建成本较高的对象,或者当系统需要独立于对象创建和构成的方式时。

声明克隆方法的接口

实现克隆方法的具体类

通过复制原型来创建新对象

浅拷贝:

使用 Object.clone() 方法直接调用 super.clone(),依赖 JVM 的默认浅拷贝行为,复制字段值(包括引用地址)。
// 1. 原型接口
interface Prototype extends Cloneable {
    Prototype clone();
}

// 2. 具体原型
class ConcretePrototype implements Prototype {
    private String field;
    private List<String> listField;
    
    public ConcretePrototype(String field, List<String> list) {
        this.field = field;
        this.listField = list;
    }
    
    // 浅拷贝实现
    public Prototype clone() {
        try {
            return (ConcretePrototype)super.clone();
        } catch (CloneNotSupportedException e) {
            return null;
        }
    }
    
    // getters and setters
}

// 3. 客户端使用
public class Client {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("item1");
        
        ConcretePrototype original = new ConcretePrototype("value", list);
        ConcretePrototype copy = (ConcretePrototype)original.clone();
        
        System.out.println(original == copy);  // false - 不同对象
        System.out.println(original.getListField() == copy.getListField());  // true - 共享引用
    }
}

深拷贝:

手动创建新对象并复制数据显式通过 new 和构造函数创建新对象,并复制引用类型字段的实际内容。
class ConcretePrototype implements Prototype {
    private String field;
    private List<String> listField;
    
    public ConcretePrototype(String field, List<String> list) {
        this.field = field;
        this.listField = new ArrayList<>(list);  // 防御性复制
    }
    
    // 深拷贝实现
    public Prototype clone() {
        List<String> newList = new ArrayList<>(this.listField);
        return new ConcretePrototype(this.field, newList);
    }
    
    // getters and setters
}

// 客户端使用
public class Client {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("item1");
        
        ConcretePrototype original = new ConcretePrototype("value", list);
        ConcretePrototype copy = (ConcretePrototype)original.clone();
        
        System.out.println(original == copy);  // false
        System.out.println(original.getListField() == copy.getListField());  // false
    }
}

应用场景:对象创建成本高

优点:

性能优化:避免重复初始化操作

灵活性:动态添加和删除产品

简化创建结构:避免复杂的创建层次

保护性拷贝:可以方便地实现防御性编程

缺点:

深拷贝实现复杂:特别是对象包含循环引用时

需要克隆方法:每个类都需要正确实现克隆方法

可能违反封装:需要暴露对象内部细节来实现克隆

简单工厂:

角色:抽象产品(定义产品的接口或抽象类)、具体产品(实现抽象产品的具体类)、工厂类(根据参数创建并返回具体产品的实例)

代码示例:

// 1. 抽象产品:定义接口
interface Shape {
    void draw();
}

// 2. 具体产品:实现接口
class Circle implements Shape {
    @Override
    public void draw() {
        System.out.println("绘制圆形");
    }
}

class Rectangle implements Shape {
    @Override
    public void draw() {
        System.out.println("绘制矩形");
    }
}

// 3. 工厂类:根据参数创建对象
class ShapeFactory {
    public Shape createShape(String type) {
        if ("circle".equalsIgnoreCase(type)) {
            return new Circle();
        } else if ("rectangle".equalsIgnoreCase(type)) {
            return new Rectangle();
        }
        throw new IllegalArgumentException("未知图形类型: " + type);
    }
}

// 4. 客户端使用
public class Client {
    public static void main(String[] args) {
        ShapeFactory factory = new ShapeFactory();
        Shape shape = factory.createShape("circle");
        shape.draw(); // 输出:绘制圆形
    }
}
 缺点与局限
  1. 违反开闭原则(OCP)
    新增产品类型(如 Triangle)需修改工厂类的 createShape() 方法。

  2. 工厂类职责过重
    所有产品的创建逻辑集中在一个类中,可能导致代码臃肿。

适用于产品类型固定、无需频繁扩展的场景。尽管其 违反开闭原则,但在小型项目或快速开发中仍具有实用价值。对于复杂系统,建议结合工厂方法或抽象工厂模式提升扩展性。

3.工厂方法:

核心思想是 将对象的创建延迟到子类。通过定义一个创建对象的接口,但让子类决定具体实例化哪个类,实现 对象创建与使用的解耦,符合开闭原则(对扩展开放,对修改关闭)。

角色:抽象产品(定义产品的接口或抽象类)、具体产品(实现抽象产品的具体类)、抽象工厂(声明工厂方法,返回抽象产品类型)、具体工厂(实现工厂方法,生成具体产品)

代码示例:

// 1. 抽象产品
interface Document {
    void open();
    void save();
}

// 2. 具体产品
class WordDocument implements Document {
    @Override
    public void open() { System.out.println("打开Word文档"); }
    @Override
    public void save() { System.out.println("保存Word文档"); }
}

class PDFDocument implements Document {
    @Override
    public void open() { System.out.println("打开PDF文档"); }
    @Override
    public void save() { System.out.println("保存PDF文档"); }
}

// 3. 抽象工厂
interface DocumentFactory {
    Document createDocument();
}

// 4. 具体工厂
class WordFactory implements DocumentFactory {
    @Override
    public Document createDocument() {
        return new WordDocument();
    }
}

class PDFFactory implements DocumentFactory {
    @Override
    public Document createDocument() {
        return new PDFDocument();
    }
}

// 5. 客户端使用
public class Client {
    public static void main(String[] args) {
        DocumentFactory factory = new WordFactory();
        Document doc = factory.createDocument();
        doc.open(); // 输出:打开Word文档
    }
}
核心优点
  1. 符合开闭原则
    新增产品类型时,只需添加对应的具体工厂和产品类,无需修改已有代码。

  2. 解耦客户端与具体类
    客户端仅依赖抽象接口(Document 和 DocumentFactory),不直接耦合具体实现。

  3. 支持多态性
    工厂方法可返回不同子类对象,实现灵活的对象创建逻辑。

缺点
  1. 类数量膨胀
    每个产品需对应一个工厂类,增加系统复杂度。

  2. 抽象性要求高
    需要预先设计抽象层,对简单场景可能过度设计。

适用场景
  • 对象类型不确定:需运行时动态决定创建哪种对象(如配置文件驱动)。

  • 扩展性强:预期系统需频繁新增产品类型(如插件系统)。

  • 框架设计:允许用户自定义组件(如Spring的BeanFactory)。

4.抽象工厂

模式定义

抽象工厂模式是一种创建型设计模式,提供 创建一系列相关或相互依赖对象的接口,而无需指定它们的具体类。其核心是 围绕产品族(一组有逻辑关联的产品)进行对象创建,确保同一族的产品能协同工作。

核心结构

抽象工厂模式包含以下角色:

  1. 抽象工厂(Abstract Factory)

    定义创建一系列产品对象的接口(如createButton()createCheckbox())。
  2. 具体工厂(Concrete Factory)

    实现抽象工厂接口,生产同一产品族的对象(如WindowsFactory生产Windows风格组件)。
  3. 抽象产品(Abstract Product)

    定义一类产品的接口(如ButtonCheckbox)。
  4. 具体产品(Concrete Product)

    实现抽象产品接口的具体类(如WindowsButtonMacCheckbox)。
代码示例
步骤1:定义抽象产品
// 按钮抽象接口
interface Button {
    void render();
}

// 复选框抽象接口
interface Checkbox {
    void check();
}

步骤2:定义具体产品

// Windows风格按钮
class WindowsButton implements Button {
    @Override
    public void render() {
        System.out.println("渲染一个Windows风格按钮");
    }
}

// Mac风格按钮
class MacButton implements Button {
    @Override
    public void render() {
        System.out.println("渲染一个Mac风格按钮");
    }
}

// Windows风格复选框
class WindowsCheckbox implements Checkbox {
    @Override
    public void check() {
        System.out.println("勾选Windows风格复选框");
    }
}

// Mac风格复选框
class MacCheckbox implements Checkbox {
    @Override
    public void check() {
        System.out.println("勾选Mac风格复选框");
    }
}

步骤3:定义抽象工厂

interface GUIFactory {
    Button createButton();
    Checkbox createCheckbox();
}

步骤4:实现具体工厂

// Windows工厂生产同一族产品
class WindowsFactory implements GUIFactory {
    @Override
    public Button createButton() {
        return new WindowsButton();
    }

    @Override
    public Checkbox createCheckbox() {
        return new WindowsCheckbox();
    }
}

// Mac工厂生产同一族产品
class MacFactory implements GUIFactory {
    @Override
    public Button createButton() {
        return new MacButton();
    }

    @Override
    public Checkbox createCheckbox() {
        return new MacCheckbox();
    }
}

步骤5:客户端使用

public class Application {
    private Button button;
    private Checkbox checkbox;

    public Application(GUIFactory factory) {
        button = factory.createButton();
        checkbox = factory.createCheckbox();
    }

    public void renderUI() {
        button.render();
        checkbox.check();
    }

    public static void main(String[] args) {
        // 根据配置选择工厂
        GUIFactory factory;
        String osType = System.getProperty("os.name").toLowerCase();
        if (osType.contains("windows")) {
            factory = new WindowsFactory();
        } else {
            factory = new MacFactory();
        }

        Application app = new Application(factory);
        app.renderUI();
    }
}
模式优势

强产品族一致性:确保同一工厂创建的对象兼容(如所有组件风格统一)。

客户端与具体类解耦:客户端仅依赖抽象接口,不关心具体实现。

易于切换产品族:通过替换工厂实例,可快速切换整套产品(如从Windows主题切换为Mac主题)。

模式缺点

新增产品困难:若需在已有产品族中增加新产品(如新增RadioButton),需修改所有工厂接口和实现类,违反开闭原则。

类数量膨胀:每新增一个产品族,需新增多个具体产品类和工厂类

适用场景
  1. 跨平台UI开发

    不同操作系统的按钮、菜单、对话框需要风格一致。
  2. 数据库兼容

    支持多种数据库(MySQL、Oracle),同一族产品包括Connection、Statement、ResultSet。
  3. 游戏引擎

    为不同画质等级(低、中、高)创建配套的模型、贴图、特效。
对比工厂方法模式
维度工厂方法模式抽象工厂模式
核心目标创建单一产品创建相关产品族
扩展方向新增产品类型(垂直扩展)新增产品族(水平扩展)
代码复杂度较低(一个工厂对应一个产品)较高(一个工厂对应多个产品)
典型场景支付方式(支付宝、微信)跨平台UI组件、数据库驱动兼容

总结

抽象工厂模式是 管理复杂对象创建 的利器,尤其适合需要保证多对象协同工作的场景。尽管存在扩展性限制,但在产品族明确且稳定的系统中,它能显著提升代码的可维护性和灵活性。

5.创建者模式

模式定义

建造者模式是一种 创建型设计模式,用于 分步骤构建复杂对象。它通过将对象的构造过程与表示分离,使得 相同的构建过程可以创建不同的对象形式
核心价值

简化多参数对象的创建(尤其当参数可选或存在依赖时)。

提高代码可读性(链式调用更直观)。

支持构造过程的精细化控制(如必填字段校验)。

核心结构

建造者模式通常包含以下角色:

  1. 产品(Product)

    最终要构建的复杂对象(如 Computer)。
  2. 抽象建造者(Builder)

    定义构造产品的通用步骤接口(如 setCPU()setRAM())。
  3. 具体建造者(Concrete Builder)

    实现抽象建造者接口,提供具体的构造逻辑。
  4. 指挥者(Director,可选)

    控制构造流程(如定义标准化的组装步骤)。
     

代码示例:自定义电脑配置

步骤1:定义产品类

public class Computer {
    private String cpu;      // 必填
    private String ram;      // 必填
    private String ssd;      // 可选
    private String gpu;      // 可选

    public Computer(String cpu, String ram, String ssd, String gpu) {
        this.cpu = cpu;
        this.ram = ram;
        this.ssd = ssd;
        this.gpu = gpu;
    }

    // 省略Getter方法...
}

步骤2:定义建造者接口

public interface ComputerBuilder {
    ComputerBuilder setCPU(String cpu);  // 必填
    ComputerBuilder setRAM(String ram);  // 必填
    ComputerBuilder setSSD(String ssd);  // 可选
    ComputerBuilder setGPU(String gpu);  // 可选
    Computer build();                   // 最终构建方法
}

步骤3:实现具体建造者

public class StandardComputerBuilder implements ComputerBuilder {
    private String cpu;
    private String ram;
    private String ssd;
    private String gpu;

    @Override
    public ComputerBuilder setCPU(String cpu) {
        this.cpu = cpu;
        return this;
    }

    @Override
    public ComputerBuilder setRAM(String ram) {
        this.ram = ram;
        return this;
    }

    @Override
    public ComputerBuilder setSSD(String ssd) {
        this.ssd = ssd;
        return this;
    }

    @Override
    public ComputerBuilder setGPU(String gpu) {
        this.gpu = gpu;
        return this;
    }

    @Override
    public Computer build() {
        // 校验必填参数
        if (cpu == null || ram == null) {
            throw new IllegalArgumentException("CPU和RAM是必填参数");
        }
        return new Computer(cpu, ram, ssd, gpu);
    }
}

步骤4:客户端使用

public class Client {
    public static void main(String[] args) {
        Computer gamingPC = new StandardComputerBuilder()
                .setCPU("Intel i9")    // 链式调用
                .setRAM("32GB")
                .setGPU("RTX 4090")
                .build();

        Computer officePC = new StandardComputerBuilder()
                .setCPU("Intel i5")
                .setRAM("8GB")
                .setSSD("512GB")
                .build();
    }
}
模式优势

参数灵活:可选参数无需传递null,避免构造方法爆炸。

代码可读性高:链式调用清晰表达参数含义(如 .setCPU("i7"))。

构造过程可控:支持参数校验、分步构建(如先设置必填项,再添加可选项)。

适用场景
  1. 复杂对象的创建

    对象包含多个部件(如订单包含商品、用户、地址等)。
  2. 参数存在依赖关系

    例如,选择“高性能模式”时自动启用特定配置。
  3. 不可变对象的构建

    通过建造者一次性设置所有参数,避免对象状态中途修改。

总结

建造者模式是处理 多参数对象创建 的最佳实践,尤其适合以下场景:

参数存在大量可选或依赖关系。

需要提高代码可读性和可维护性。

希望支持灵活的构造过程(如参数校验、分步构建)。

通过链式调用和分离构造逻辑,它能显著简化复杂对象的创建,是Java开发者工具箱中的必备设计模式。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值