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); }
|

可以看到,通过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); } }
|

解决:
- 修改clone方法
1 2 3 4
| @Override protected Object clone() throws CloneNotSupportedException { return getInstance(); }
|
- 避免单例类实现 Cloneable
3. JDK的使用
实现了Cloneable的类