原型模式、建造者模式
原型模式
原型模式(Prototype Pattern)是一种创建型设计模式,它允许你通过复制现有对象来创建新对象,而不是通过实例化类。这种模式在需要大量相似对象时非常有用,因为它可以减少创建对象的开销。
原型模式的應用場景
- 性能和资源管理:当创建对象的代价较大时,可以使用原型模式减少创建对象的开销。
- 避免构造函数的复杂性:如果对象的创建过程非常复杂,可以通过克隆已有对象来简化创建过程。
- 隔离复杂对象的创建:在某些情况下,直接使用构造函数可能会使代码变得复杂,而通过克隆可以简化代码。
- 缓存实例:在某些场景下,可以预先创建一些对象并缓存起来,需要时直接克隆这些对象。
Java 原型模式的代碼實例
以下是一个简单的Java示例,展示了如何使用原型模式:
// 定义一个抽象的原型接口
interface Prototype {Prototype clone();
}// 实现具体的原型类
class ConcretePrototype implements Prototype {private String field;public ConcretePrototype(String field) {this.field = field;}@Overridepublic Prototype clone() {return new ConcretePrototype(this.field);}@Overridepublic 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; }@Overridepublic 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 {@Overridepublic void buildPartA() {product.setPartA("Part A");}@Overridepublic void buildPartB() {product.setPartB("Part B");}@Overridepublic 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