簡介
原型模式(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;
}
}
深拷貝將原型所依賴的對象 也拷貝了一份
內存圖如下