原型模式、建造者模式
原型模式
原型模式(Prototype Pattern)是一种创建型设计模式,它允许你通过复制现有对象来创建新对象,而不是通过实例化类。这种模式在需要大量相似对象时非常有用,因为它可以减少创建对象的开销。
原型模式的應用場景
- 性能和资源管理:当创建对象的代价较大时,可以使用原型模式减少创建对象的开销。
 - 避免构造函数的复杂性:如果对象的创建过程非常复杂,可以通过克隆已有对象来简化创建过程。
 - 隔离复杂对象的创建:在某些情况下,直接使用构造函数可能会使代码变得复杂,而通过克隆可以简化代码。
 - 缓存实例:在某些场景下,可以预先创建一些对象并缓存起来,需要时直接克隆这些对象。
 
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);
    }
}
 
在这个示例中:
Prototype接口定义了一个clone方法,用于克隆对象。ConcretePrototype类实现了Prototype接口,并提供了clone方法的具体实现。- 在客户端代码中,我们创建了一个原始对象,并通过调用
clone方法创建了它的副本。 
这样,通过原型模式,我们可以方便地创建对象的副本,而不需要每次都通过构造函数来创建新的对象。
建造者模式
建造者模式(Builder Pattern)是一种创建型设计模式,它允许你通过一步一步地构建复杂对象。这种模式特别适用于需要创建具有多个可选参数的对象时,可以避免构造函数参数过多的问题。
建造者模式的應用場景
- 复杂对象的创建:当一个对象有很多属性,并且这些属性可能有不同的组合时,使用建造者模式可以简化对象的创建过程。
 - 避免构造函数参数过多:如果一个类的构造函数有多个参数,使用建造者模式可以使代码更加清晰和易于维护。
 - 不可变对象:在创建不可变对象时,建造者模式可以帮助确保对象在构建过程中不会被修改。
 - 流式接口:建造者模式通常提供流式接口,使代码更具可读性。
 
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);
    }
}
 
在这个示例中:
Product类是我们要构建的复杂对象。Builder是一个抽象类,定义了构建不同部分的方法。ConcreteBuilder是具体的建造者类,实现了Builder类的方法。Director类负责控制建造过程,按照一定的顺序调用建造者的方法。- 在客户端代码中,我们创建了一个具体的建造者实例和一个指挥者实例,然后通过指挥者来构建产品。
 
这样,通过建造者模式,我们可以灵活地构建复杂对象,同时保持代码的清晰和可维护性。
单例模式
单例模式(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










