创建型模式
单例模式(Singleton Pattern)
单例模式(Singleton Pattern)在Java中的使用场景与在其他编程语言中类似,其主要目的是确保一个类只有一个实例,并提供一个全局的访问点。以下是单例模式的一些常见使用场景及详细讲解:
使用场景
-
控制资源的使用:
- 数据库连接池:数据库连接是昂贵的资源,使用单例模式可以确保只有一个连接池实例,统一管理连接资源,避免重复创建和销毁连接,提高系统性能。
- 线程池:线程的创建和销毁开销较大,单例模式可以确保只有一个线程池实例,集中管理线程,提高系统效率。
-
全局配置管理:
- 配置文件管理:系统中的配置通常是全局的,使用单例模式可以确保配置文件只被加载一次,并且全局共享,避免多次加载造成的资源浪费。
- 日志管理器:日志系统在应用程序中通常是全局的,通过单例模式可以确保日志管理器实例的唯一性,方便统一管理日志输出。
-
状态管理:
- 缓存管理:在某些系统中,需要对一些数据进行缓存,使用单例模式可以确保缓存管理器实例的唯一性,从而保证缓存的一致性和统一管理。
- 设备管理:对于一些物理设备,如打印机或串口设备,通过单例模式可以确保设备管理器的唯一实例,避免设备被多个对象同时操作。
实现示例(Java)
下面是一个在Java中实现单例模式的示例:
饿汉式单例模式
饿汉式单例模式在类加载时就创建实例:
public class Singleton {
// 在类加载时创建实例
private static final Singleton INSTANCE = new Singleton();
// 私有化构造函数,防止外部实例化
private Singleton() {}
// 提供一个公共的访问方法
public static Singleton getInstance() {
return INSTANCE;
}
}
懒汉式单例模式
懒汉式单例模式在需要时才创建实例:
public class Singleton {
// 初始时不创建实例
private static Singleton instance;
// 私有化构造函数,防止外部实例化
private Singleton() {}
// 提供一个公共的访问方法,并使用 synchronized 关键字确保线程安全
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
双重检查锁定(Double-Checked Locking)
这种方式通过双重检查加锁,确保线程安全并提高效率:
public class Singleton {
// 使用 volatile 关键字确保多线程环境下变量的可见性
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;
}
}
使用示例
public class Main {
public static void main(String[] args) {
Singleton singleton1 = Singleton.getInstance();
Singleton singleton2 = Singleton.getInstance();
singleton1.value = 42;
System.out.println(singleton2.value); // 输出 42,证明两个引用指向同一个实例
}
}
通过上述示例,可以看出无论是饿汉式、懒汉式还是双重检查锁定,单例模式都可以确保一个类只有一个实例,并在需要时提供全局访问点。这在实际应用中有助于资源管理、状态管理和配置管理等。
建造者模式(Builder Pattern)
建造者模式(Builder Pattern)是一种创建型设计模式,它允许你分步骤创建复杂对象。通过将一个复杂对象的构造代码从其表示中分离出来,建造者模式可以让你通过细化各个部分的构造步骤来创建一个复杂对象。
适用场景
-
需要生成的对象有复杂的内部结构:
- 对象的创建过程包含多个步骤或多个部件的创建。
-
同样的创建过程需要生成不同的表示:
- 一个构建过程可以创建多个不同类型的对象。
-
客户端代码不希望直接控制对象的创建过程:
- 客户端代码只需要一个构建器来控制创建的细节。
实现示例(Java)
以下是一个简单的建造者模式的实现示例,展示如何创建不同类型的房子(如石头房子和木头房子)。
1. 产品类
public class House {
private String foundation;
private String structure;
private String roof;
private String interior;
public void setFoundation(String foundation) {
this.foundation = foundation;
}
public void setStructure(String structure) {
this.structure = structure;
}
public void setRoof(String roof) {
this.roof = roof;
}
public void setInterior(String interior) {
this.interior = interior;
}
@Override
public String toString() {
return "House [foundation=" + foundation + ", structure=" + structure + ", roof=" + roof + ", interior=" + interior + "]";
}
}
2. 抽象建造者类
public abstract class HouseBuilder {
protected House house;
public House getHouse() {
return house;
}
public void createNewHouse() {
house = new House();
}
public abstract void buildFoundation();
public abstract void buildStructure();
public abstract void buildRoof();
public abstract void buildInterior();
}
3. 具体建造者类
public class StoneHouseBuilder extends HouseBuilder {
@Override
public void buildFoundation() {
house.setFoundation("Stone foundation");
}
@Override
public void buildStructure() {
house.setStructure("Stone walls");
}
@Override
public void buildRoof() {
house.setRoof("Stone roof");
}
@Override
public void buildInterior() {
house.setInterior("Stone interior");
}
}
public class WoodenHouseBuilder extends HouseBuilder {
@Override
public void buildFoundation() {
house.setFoundation("Wooden foundation");
}
@Override
public void buildStructure() {
house.setStructure("Wooden walls");
}
@Override
public void buildRoof() {
house.setRoof("Wooden roof");
}
@Override
public void buildInterior() {
house.setInterior("Wooden interior");
}
}
4. 指挥者类
public class Director {
private HouseBuilder houseBuilder;
public void setHouseBuilder(HouseBuilder houseBuilder) {
this.houseBuilder = houseBuilder;
}
public House getHouse() {
return houseBuilder.getHouse();
}
public void constructHouse() {
houseBuilder.createNewHouse();
houseBuilder.buildFoundation();
houseBuilder.buildStructure();
houseBuilder.buildRoof();
houseBuilder.buildInterior();
}
}
5. 客户端代码
public class Client {
public static void main(String[] args) {
Director director = new Director();
// 建造石头房子
HouseBuilder stoneHouseBuilder = new StoneHouseBuilder();
director.setHouseBuilder(stoneHouseBuilder);
director.constructHouse();
House stoneHouse = director.getHouse();
System.out.println("House built:\n" + stoneHouse);
// 建造木头房子
HouseBuilder woodenHouseBuilder = new WoodenHouseBuilder();
director.setHouseBuilder(woodenHouseBuilder);
director.constructHouse();
House woodenHouse = director.getHouse();
System.out.println("House built:\n" + woodenHouse);
}
}
注释说明
-
产品类:
House
类表示一个复杂对象。它有多个部件(如基础、结构、屋顶和内部装饰)。
-
抽象建造者类:
HouseBuilder
是一个抽象类,定义了构建House
对象的各个步骤(如buildFoundation
、buildStructure
等)。
-
具体建造者类:
StoneHouseBuilder
和WoodenHouseBuilder
是具体的建造者类,实现了抽象建造者类的方法,具体定义了如何构建House
的各个部件。
-
指挥者类:
Director
类负责管理建造过程。它通过调用HouseBuilder
的方法来一步步构建House
对象。
-
客户端代码:
Client
类通过Director
类来构建不同类型的房子。客户端代码不需要直接控制对象的创建过程,只需要使用Director
来管理建造者。
总结
建造者模式通过将复杂对象的构建过程分离出来,使得客户端代码可以灵活地构建不同类型的对象。它适用于需要构建复杂对象的场景,尤其是当对象的创建过程包含多个步骤或多个部件时。建造者模式可以提高代码的可读性和可维护性。
原型模式(Prototype Pattern)
原型模式(Prototype Pattern)是一种创建型设计模式,它允许一个对象通过克隆自身来创建新的对象。使用原型模式,可以避免创建对象时涉及复杂的初始化步骤,同时也可以方便地复制已有对象的状态。
适用场景
-
对象的创建成本很高:
- 当对象的创建成本很高,且可以通过复制来减少成本时,可以使用原型模式。
-
对象的初始化复杂:
- 对象的初始化需要很多步骤,而这些步骤又可能会有所变化,使用原型模式可以简化这些步骤。
-
需要大量相似对象:
- 当需要大量相似对象时,可以通过复制原型来快速创建新对象。
实现示例(Java)
以下是一个简单的原型模式的实现示例,展示如何克隆不同类型的形状(如圆形和矩形)。
1. 定义原型接口
public interface Shape extends Cloneable {
Shape clone();
void draw();
}
2. 具体原型类实现接口
public class Circle implements Shape {
private int radius;
public Circle(int radius) {
this.radius = radius;
}
@Override
public Circle clone() {
return new Circle(this.radius);
}
@Override
public void draw() {
System.out.println("Drawing a circle with radius: " + radius);
}
}
public class Rectangle implements Shape {
private int width;
private int height;
public Rectangle(int width, int height) {
this.width = width;
this.height = height;
}
@Override
public Rectangle clone() {
return new Rectangle(this.width, this.height);
}
@Override
public void draw() {
System.out.println("Drawing a rectangle with width: " + width + " and height: " + height);
}
}
3. 客户端代码
public class Client {
public static void main(String[] args) {
// 创建原型对象
Circle originalCircle = new Circle(5);
Rectangle originalRectangle = new Rectangle(3, 4);
// 克隆对象
Circle clonedCircle = originalCircle.clone();
Rectangle clonedRectangle = originalRectangle.clone();
// 使用克隆对象
originalCircle.draw();
clonedCircle.draw();
originalRectangle.draw();
clonedRectangle.draw();
}
}
注释说明
-
原型接口:
Shape
接口继承了Cloneable
接口,并定义了clone
和draw
方法。clone
方法用于克隆对象,draw
方法用于绘制形状。
-
具体原型类:
Circle
和Rectangle
类实现了Shape
接口,并提供了自己的clone
和draw
方法。clone
方法使用当前对象的状态创建一个新对象。
-
客户端代码:
Client
类创建了原型对象(如Circle
和Rectangle
),然后通过调用clone
方法克隆这些对象,并使用克隆的对象。
总结
原型模式通过克隆现有对象来创建新对象,适用于对象创建成本高、初始化复杂或需要大量相似对象的场景。它能够简化对象创建过程,提高代码的灵活性和可维护性。