问题:有时候需要一个和已有对象一模一样的对象时,如果用new的方式通过构造器来新造一个对象,会非常耗费资源和比较复杂。
原型模式是直接克隆出一个一模一样的对象,创建对象非常高效,无需知道对象创建细节。
原型实例指定了要创建的对象的种类。
原型模式(prototype)
原形模式的写法其实很简单,分为两步:
- 实现Cloneable接口
- 重写clone非法
要被克隆的类
// 图片
public class IMG implements Cloneable{//1.实现Cloneable接口
String name = null;
Date date = null;
public IMG(String name, Date date) {
this.name = name;
this.date = date;
}
@Override
public String toString() {
return "IMG{" +
"name='" + name + '\'' +
", date=" + date +
'}';
}
//2.重写clone方法
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
克隆
public class CopyIMG {
public static void main(String[] args) throws Exception {
Date date = new Date();
IMG img1 = new IMG("王冰冰", date);
System.out.println("img1>"+img1);
System.out.println("img1.hash>" + img1.hashCode());
IMG img2 = (IMG) img1.clone();
System.out.println("img2>"+img2);
System.out.println("img2.hash>" + img2.hashCode());
}
}
输出(可以看到对象的内容一致,但不是同一个对象了,hashcode的值不同)
img1>IMG{name=‘王冰冰’, date=Tue Jan 05 21:57:09 CST 2021}
img1.hash>325040804
img2>IMG{name=‘王冰冰’, date=Tue Jan 05 21:57:09 CST 2021}
img2.hash>1173230247Process finished with exit code 0
但以上写法在某种情况下好像就不对了
预期:克隆完无论原对象怎么改变,克隆对象都是保存在克隆时那个状态,除非主动改变克隆对象。
public class CopyIMG {
public static void main(String[] args) throws Exception {
Date date = new Date();
IMG img1 = new IMG("王冰冰", date);
IMG img2 = (IMG) img1.clone();//已经克隆结束
//克隆结束后修改原对象的值
img1.getDate().setTime(45648973);
System.out.println("img1>"+img1);
System.out.println("img1.hash>" + img1.hashCode());
System.out.println("img2>"+img2);
System.out.println("img2.hash>" + img2.hashCode());
}
}
输出
img1>IMG{name=‘王冰冰’, date=Thu Jan 01 20:40:48 CST 1970}
img1.hash>325040804
img2>IMG{name=‘王冰冰’, date=Thu Jan 01 20:40:48 CST 1970}
img2.hash>1173230247Process finished with exit code 0
和预期的不一致,克隆后的对象应显示的时间应该要为当前的时间才对!
其实这里涉及了浅拷贝和深拷贝,学过C++的朋友应该就比较了解,这里只是单纯的把date对象的地址复制过去,而不是克隆一个新的date对象。
内存现状
深拷贝
修改IMG的clone方法
@Override
protected Object clone() throws CloneNotSupportedException {
IMG clone = (IMG) super.clone();
clone.date = (Date) date.clone();
return clone;
}
把date对象也克隆了。
输出
img1>IMG{name=‘王冰冰’, date=Thu Jan 01 20:40:48 CST 1970}
img1.hash>325040804
img2>IMG{name=‘王冰冰’, date=Tue Jan 05 22:18:08 CST 2021}
img2.hash>1173230247Process finished with exit code 0
内存状态