当前位置: 首页 > article >正文

Java 原型模式、建造者模式、单例模式

原型模式、建造者模式

原型模式

原型模式(Prototype Pattern)是一种创建型设计模式,它允许你通过复制现有对象来创建新对象,而不是通过实例化类。这种模式在需要大量相似对象时非常有用,因为它可以减少创建对象的开销。

原型模式的應用場景

  1. 性能和资源管理:当创建对象的代价较大时,可以使用原型模式减少创建对象的开销。
  2. 避免构造函数的复杂性:如果对象的创建过程非常复杂,可以通过克隆已有对象来简化创建过程。
  3. 隔离复杂对象的创建:在某些情况下,直接使用构造函数可能会使代码变得复杂,而通过克隆可以简化代码。
  4. 缓存实例:在某些场景下,可以预先创建一些对象并缓存起来,需要时直接克隆这些对象。

Java 原型模式的代碼實例

以下是一个简单的Java示例,展示了如何使用原型模式:

// 定义一个抽象的原型接口
interface Prototype {
    Prototype clone();
}

// 实现具体的原型类
class ConcretePrototype implements Prototype {
    private String field;

    public ConcretePrototype(String field) {
        this.field = field;
    }

    @Override
    public Prototype clone() {
        return new ConcretePrototype(this.field);
    }

    @Override
    public String toString() {
        return "ConcretePrototype{" +
                "field='" + field + '\'' +
                '}';
    }
}

// 客户端代码
public class PrototypePatternDemo {
    public static void main(String[] args) {
        // 创建一个原始对象
        ConcretePrototype original = new ConcretePrototype("Original");
        System.out.println("Original: " + original);

        // 克隆原始对象
        ConcretePrototype clone = (ConcretePrototype) original.clone();
        System.out.println("Clone: " + clone);
    }
}

在这个示例中:

  1. Prototype接口定义了一个clone方法,用于克隆对象。
  2. ConcretePrototype类实现了Prototype接口,并提供了clone方法的具体实现。
  3. 在客户端代码中,我们创建了一个原始对象,并通过调用clone方法创建了它的副本。

这样,通过原型模式,我们可以方便地创建对象的副本,而不需要每次都通过构造函数来创建新的对象。


建造者模式

建造者模式(Builder Pattern)是一种创建型设计模式,它允许你通过一步一步地构建复杂对象。这种模式特别适用于需要创建具有多个可选参数的对象时,可以避免构造函数参数过多的问题。

建造者模式的應用場景

  1. 复杂对象的创建:当一个对象有很多属性,并且这些属性可能有不同的组合时,使用建造者模式可以简化对象的创建过程。
  2. 避免构造函数参数过多:如果一个类的构造函数有多个参数,使用建造者模式可以使代码更加清晰和易于维护。
  3. 不可变对象:在创建不可变对象时,建造者模式可以帮助确保对象在构建过程中不会被修改。
  4. 流式接口:建造者模式通常提供流式接口,使代码更具可读性。

Java 建造者模式的代碼實例

以下是一个简单的Java示例,展示了如何使用建造者模式:

// 产品类
class Product {
    private String partA;
    private String partB;
    private String partC;

    public void setPartA(String partA) { this.partA = partA; }
    public void setPartB(String partB) { this.partB = partB; }
    public void setPartC(String partC) { this.partC = partC; }

    @Override
    public String toString() {
        return "Product{" +
                "partA='" + partA + '\'' +
                ", partB='" + partB + '\'' +
                ", partC='" + partC + '\'' +
                '}';
    }
}

// 抽象建造者类
abstract class Builder {
    protected Product product = new Product();

    public abstract void buildPartA();
    public abstract void buildPartB();
    public abstract void buildPartC();

    public Product getResult() {
        return product;
    }
}

// 具体建造者类
class ConcreteBuilder extends Builder {
    @Override
    public void buildPartA() {
        product.setPartA("Part A");
    }

    @Override
    public void buildPartB() {
        product.setPartB("Part B");
    }

    @Override
    public void buildPartC() {
        product.setPartC("Part C");
    }
}

// 指挥者类
class Director {
    private Builder builder;

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

    public void construct() {
        builder.buildPartA();
        builder.buildPartB();
        builder.buildPartC();
    }
}

// 客户端代码
public class BuilderPatternDemo {
    public static void main(String[] args) {
        Builder builder = new ConcreteBuilder();
        Director director = new Director(builder);
        director.construct();
        Product product = builder.getResult();
        System.out.println(product);
    }
}

在这个示例中:

  1. Product类是我们要构建的复杂对象。
  2. Builder是一个抽象类,定义了构建不同部分的方法。
  3. ConcreteBuilder是具体的建造者类,实现了Builder类的方法。
  4. Director类负责控制建造过程,按照一定的顺序调用建造者的方法。
  5. 在客户端代码中,我们创建了一个具体的建造者实例和一个指挥者实例,然后通过指挥者来构建产品。

这样,通过建造者模式,我们可以灵活地构建复杂对象,同时保持代码的清晰和可维护性。


单例模式

单例模式(Singleton Pattern)是Java设计模式中最简单的一种,它确保一个类在整个应用程序运行期间只有一个实例,并提供一个全局访问点。这种模式在需要控制资源唯一性或对共享资源进行管理时非常有用。

单例模式是一种创建型设计模式,其目的是确保某个类在系统中只有一个实例存在,并提供一个全局访问该实例的方法。通过这种方式,可以有效地控制资源的使用,避免不必要的实例化开销。单例模式适用于以下场景:

  • 需要控制资源的唯一性,如数据库连接池、配置文件管理器等。
  • 需要对共享资源进行集中管理,如线程池、日志记录器等。

二、单例模式的实现方式

单例模式有多种实现方法,主要包括懒汉式、饿汉式、双重检查锁和静态内部类。每种方法都有其优缺点,适用于不同的场景。

1. 懒汉式(Lazy Initialization)

懒汉式单例模式只有在第一次使用时才会创建实例。这种方式适用于实例化开销较大的对象,且该对象在程序运行初期不一定会被使用。

代码示例:

public class LazySingleton {
    private static LazySingleton instance;

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

    public static synchronized LazySingleton getInstance() {
        if (instance == null) {
            instance = new LazySingleton();
        }
        return instance;
    }
}

适用场景:

  • 实例化开销较大的对象。
  • 程序启动时不需要立即加载的对象。

优缺点:

  • 优点:延迟加载,减少内存开销。
  • 缺点:多线程环境下性能较差,因为每次获取实例时都需要进行同步。
2. 饿汉式(Eager Initialization)

饿汉式单例模式在类加载时就创建实例,适用于程序运行过程中必然会使用到的实例。

代码示例:

public class EagerSingleton {
    private static final EagerSingleton instance = new EagerSingleton();

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

    public static EagerSingleton getInstance() {
        return instance;
    }
}

适用场景:

  • 启动时需要立即加载并长期使用的对象。

优缺点:

  • 优点:实现简单,线程安全。
  • 缺点:由于实例是在类加载时创建的,可能会导致内存浪费,尤其是在实例一直没有被使用的情况下。
3. 双重检查锁(Double-Check Locking)

双重检查锁机制在多线程环境下使用,确保实例的唯一性和线程安全性。

代码示例:

public class DoubleCheckedLockingSingleton {
    private static volatile DoubleCheckedLockingSingleton instance;

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

    public static DoubleCheckedLockingSingleton getInstance() {
        if (instance == null) {
            synchronized (DoubleCheckedLockingSingleton.class) {
                if (instance == null) {
                    instance = new DoubleCheckedLockingSingleton();
                }
            }
        }
        return instance;
    }
}

适用场景:

  • 需要延迟加载单例对象且需要确保多线程安全的场景。

优缺点:

  • 优点:线程安全,避免了不必要的同步开销。
  • 缺点:实现复杂,可能会增加代码的可维护性难度。
4. 静态内部类(Static Inner Class)

利用Java的类加载机制,静态内部类实现单例模式既实现了延迟加载,又保证了线程安全。

代码示例:

public class StaticInnerClassSingleton {
    private StaticInnerClassSingleton() {
        // 私有化构造函数
    }

    private static class SingletonHelper {
        private static final StaticInnerClassSingleton INSTANCE = new StaticInnerClassSingleton();
    }

    public static StaticInnerClassSingleton getInstance() {
        return SingletonHelper.INSTANCE;
    }
}

适用场景:

  • 需要延迟加载但不希望增加代码复杂度的场景。

优缺点:

  • 优点:延迟加载,线程安全,且实现简单。
  • 缺点:无法在实例化时传递参数。

三、单例模式的应用场景

单例模式在实际应用中非常广泛,特别是在需要控制资源唯一性的场合。以下是几个典型的应用场景:

1. 配置管理器

在一个电商系统中,各种配置如数据库连接、API密钥等通常都是全局的且不会频繁更改。这些配置数据可以封装在一个配置管理器类中,并使用单例模式来确保只有一个实例来管理所有配置。

代码示例:

public class ConfigurationManager {
    private static ConfigurationManager instance;
    private Properties properties;

    private ConfigurationManager() {
        properties = new Properties();
        // 加载配置文件
        try (InputStream input = new FileInputStream("config.properties")) {
            properties.load(input);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static synchronized ConfigurationManager getInstance() {
        if (instance == null) {
            instance = new ConfigurationManager();
        }
        return instance;
    }

    // 获取配置信息的方法
    public String getProperty(String key) {
        return properties.getProperty(key);
    }
}

在这个例子中,ConfigurationManager类使用了懒汉式单例模式,确保配置文件只被加载一次,并且在应用程序的任何地方都可以通过ConfigurationManager.getInstance()来获取配置实例。

2. 数据库连接池

数据库连接池是用来管理和复用数据库连接的对象。为了避免频繁创建和销毁连接带来的性能开销,可以使用单例模式来管理连接池。

代码示例:

public class DatabaseConnectionPool {
    private static DatabaseConnectionPool instance;
    private List<Connection> connections;

    private DatabaseConnectionPool() {
        connections = new ArrayList<>();
        // 初始化连接池中的连接
        for (int i = 0; i < 10; i++) {
            connections.add(createConnection());
        }
    }

    public static synchronized DatabaseConnectionPool getInstance() {
        if (instance == null) {
            instance = new DatabaseConnectionPool();
        }
        return instance;
    }

    // 获取连接的方法
    public Connection getConnection() {
        if (connections.isEmpty()) {
            throw new SQLException("No available connections");
        } else {
            return connections.remove(connections.size() - 1);
        }
    }

    // 释放连接的方法
    public void releaseConnection(Connection connection) {
        connections.add(connection);
    }
}

在这个例子中,DatabaseConnectionPool类使用了懒汉式单例模式,确保连接池只被初始化一次,并且在应用程序的任何地方都可以通过DatabaseConnectionPool.getInstance()来获取连接池实例。

3. 日志记录器

在大型应用中,日志记录通常由一个集中的日志记录器负责。通过单例模式,可以确保日志记录器的唯一性,避免多个实例导致的日志混乱。

代码示例:

public class Logger {
    private static Logger instance;
    private static List<String> logEntries;

    private Logger() { }

    public static synchronized Logger getInstance() {
        if (instance == null) {
            instance = new Logger();
            logEntries = new ArrayList<>();
        }
        return instance;
    }

    // 记录日志的方法
    public void log(String message) {
        logEntries.add(message);
        System.out.println(message); // 输出到控制台,也可以输出到文件或其他介质
    }
}

在这个例子中,Logger类使用了懒汉式单例模式,确保日志记录器只被初始化一次,并且在应用程序的任何地方都可以通过Logger.getInstance()来获取日志记录器实例。


END


http://www.kler.cn/a/488241.html

相关文章:

  • 【SOC 芯片设计 DFT 学习专栏 -- RTL 中的信号名和 Netlist 中的信号名差异】
  • LabVIEW 系统诊断
  • 智慧公厕大数据驱动下的公共卫生管理与优化
  • 【C++】C++11(二)
  • 【微服务】SpringBoot 整合Redis实现延时任务处理使用详解
  • 运放输入偏置电流详解
  • ESP32作为Wi-Fi STA模式的测试
  • CLIP代码相关问题
  • Python中用Open3D 可视化的点云窗口快捷键
  • 荒腔走板Mac电脑本地部署 LLM
  • MySQL使用C语言连接
  • 使用SPI机制加载实现类
  • 一文流:Maven精讲
  • 深入探索 ScottPlot.WPF:在 Windows 桌面应用中绘制精美图表的利器
  • ASP.NET Core 实现微服务 -- Polly 服务降级熔断
  • 深入浅出负载均衡:理解其原理并选择最适合你的实现方式
  • Node 之 Stream 深度剖析:从原理到项目实战应用场景全解
  • 网络安全有哪些细分方向?零基础学Web安全需要掌握的知识(附系统路线+工具笔记)
  • Vue3+TS+vite项目笔记1
  • 实战设计模式之桥接模式
  • Gin框架中间件原理
  • 24级 秋季学期期末考试安排(专升本)
  • 计算机网络(二)——物理层和数据链路层
  • Lua语言的文件IO
  • Decord - 深度学习视频加载器
  • OpenCV计算机视觉 07 图像的模块匹配