原型模式

1 概念

1 定义

原型模式(Prototype)是一种创建型设计模式,它通过克隆现有的对象来创建新的对象。部分场景下,性能要优于new来创建对象

2 应用场景

  • 类初始化消耗比较多的资源
  • new一个对象需要很繁琐的过程(数据准备,访问权限等)
  • 构造函数比较复杂
  • 循环体中产生大量对象。(避免重复执行构造函数的操作,从而提高性能和效率)

3 优缺点

优点:

  • 不需要调用构造函数,比直接new一个对象性能高
  • 简化创建过程

缺点:

  • 必须配备clone方法
  • 深拷贝和浅拷贝容易引入bug

2 代码实现

我们可以使用java.lang.Cloneable接口和clone()方法来实现原型模式

1
2
3
4
5
6
7
8
9
10
11
@Data
@AllArgsConstructor
public class Pig implements Cloneable{
private String name;
private Date birthday;

@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Test {
public static void main(String[] args) throws CloneNotSupportedException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Date birthday = new Date(0L);
Pig pig1 = new Pig("佩奇",birthday);
Pig pig2 = (Pig) pig1.clone();
System.out.println(pig1);
System.out.println(pig2);

pig1.getBirthday().setTime(666666666666L);
System.out.println("==================更新日期====================");

System.out.println(pig1);
System.out.println(pig2);
}

image-20231003175638825

可以看到,通过clone()方法通过调用复制构造函数来创建一个新的Pig对象,但是需要注意深拷贝与浅拷贝的问题。

在上面的例子中,我们期待的结果是只更新pig1的生日,但是由于pig1和pig2的生日是同一个引用,所以pīg2的生日也更新了。

clone方法做以下调整,将birthday也进行clone:

1
2
3
4
5
6
7
@Override
protected Object clone() throws CloneNotSupportedException {
Pig pig = (Pig)super.clone();
////深克隆
pig.birthday = (Date) pig.birthday.clone();
return pig;
}

3. 克隆破坏单例

1
2
3
4
5
6
7
8
9
10
11
12
13
public class HungrySingleton implements Cloneable{

private final static HungrySingleton hungrySingleton= new HungrySingleton();

public static HungrySingleton getInstance(){
return hungrySingleton;
}

@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
1
2
3
4
5
6
7
8
9
10
public class Test {
public static void main(String[] args) throws CloneNotSupportedException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
HungrySingleton hungrySingleton = HungrySingleton.getInstance();
Method method = hungrySingleton.getClass().getDeclaredMethod("clone");
method.setAccessible(true);
HungrySingleton cloneHungrySingleton = (HungrySingleton) method.invoke(hungrySingleton);
System.out.println(hungrySingleton);
System.out.println(cloneHungrySingleton);
}
}

image-20231003181533190

解决:

  1. 修改clone方法
1
2
3
4
@Override
protected Object clone() throws CloneNotSupportedException {
return getInstance();
}
  1. 避免单例类实现 Cloneable

3. JDK的使用

实现了Cloneable的类

  • arrayList
  • Hashmap
  • Object

原型模式
http://example.com/原型模式/
作者
Panyurou
发布于
2023年10月3日
许可协议