简介
原型模式(prototype) java中有一个克隆技术,以某个对象为原型,复制出新的对象。使用克隆,类似于new,但是又不同于new。这是从内存中直接复制了,使用克隆,有效率高的优点,避免了重新执行构造过程的步骤。
原型模式的实现
我们可以想象一下以下一些场景:
火影忍者中,鸣人查克拉的分生。
西游记中,孙悟空把一根毛变出一堆孙悟空。
这些情况出来的人,都不是一个一个从婴儿长大的,高效地一会儿就就能在短时间内产出。
即使是现实中的克隆羊多利,其实生命的成长也比普通羊快上不少。(据说因为他是克隆的6岁的羊,多利一生出来就是6岁,具体不知 (^__^) …)
- 在prototype模式中 我们首先要cloneable接口实现clone方法,clone方法是在object类里面的,会自动从object类中继承
public class Prototype implements Cloneable{
private String sname;
private Date birthday;
@Override
protected Object clone() throws CloneNotSupportedException {
//掉用 object 的克隆方法
return super.clone();
}
public String getSname() {
return sname;
}
public void setSname(String sname) {
this.sname = sname;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public Prototype(String sname, Date birthday) {
super();
this.sname = sname;
this.birthday = birthday;
}
}
- 下面我们定义一个 客户类用于测试
/**
* 原型方法的测试
* @author guxiang
* @date 2017-2-25 上午10:09:27
*/
public class Client {
public static void main(String[] args) throws Exception {
Prototype p1 = new Prototype("二狗",new Date());
Prototype p2 = (Prototype) p1.clone();
System.out.println(p1);
System.out.println(p1.getSname());
System.out.println(p1.getBirthday());
System.out.println("--------------");
System.out.println(p2);
System.out.println(p2.getSname());
System.out.println(p2.getBirthday());
}
}
----------
执行结果如下
com.guxiang.prototype.Prototype@6af62373
二狗
Sat Feb 25 11:26:56 CST 2017
--------------
com.guxiang.prototype.Prototype@12276af2
二狗
Sat Feb 25 11:26:56 CST 2017
在执行结果中,我们可以看到, 对象的hash值(内存地址)是不一样的,代表他们两个不是一个对象,然而对象里面属性的值 都是一样的,相当于一个克隆人,他不是你,然而属性和外表都一样。
- 上面我们讲的其实是一种浅拷贝
- -
什么是浅拷贝呢?
public class Client {
public static void main(String[] args) throws Exception {
Date date = new Date();
Prototype p1 = new Prototype("二狗",date);
System.out.println(p1);
System.out.println(p1.getSname());
System.out.println(p1.getBirthday());
Prototype p2 = (Prototype) p1.clone();
date.setTime(1235);
System.out.println("--------------");
System.out.println(p2);
System.out.println(p2.getSname());
System.out.println(p2.getBirthday());
}
}
----------
执行结果如下
com.guxiang.prototype.Prototype@6af62373
二狗
Sat Feb 25 11:50:54 CST 2017
--------------
com.guxiang.prototype.Prototype@12276af2
二狗
Thu Jan 01 08:00:01 CST 1970
我们可以看出,如果原型依赖于另外一个对象,那么clone的时候,浅拷贝只是拷贝了原型所依赖的对象的地址,而没有吧原型所依赖的对象拷贝进去。
那么怎么在原型模式中使用深拷贝呢?
我只需要在克隆的时候 把属性也克隆。
public class Prototype implements Cloneable{
private String sname;
private Date birthday;
/**
* 深拷贝的代码实现
*/
@Override
protected Object clone() throws CloneNotSupportedException {
//掉用 object 的克隆方法
Object object = super.clone();
Prototype prototype = (Prototype) object;
prototype.birthday = (Date) this.birthday.clone();
return prototype;
}
public String getSname() {
return sname;
}
public void setSname(String sname) {
this.sname = sname;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public Prototype(String sname, Date birthday) {
super();
this.sname = sname;
this.birthday = birthday;
}
}
深拷贝将原型所依赖的对象 也拷贝了一份
内存图如下