原型模式是一種比較簡單的設計模式,也非常的容易理解,屬於創建型設計模式的一種,只實現一個接口,重寫一個方法即可完成原型模式。那麼我們就來看看吧。
一、定義
用原型實例指定創建對象的種類,並通過拷貝這些原型創建新的對象。
二、適用情況
創建一些大對象,比較耗時的對象的時候,可以使用原型模式提高創建對象的效率。
三、原型模式實現
1、實現Cloneable接口,在java中有一個Cloneable接口,它的作用只有一個,就是通知虛擬機可以安全的在實現了此接口的類上使用clone()方法。如果你想看下這個接口,其實可以告訴你,並沒有什麼可看的,只是一個標識接口,實現此接口就是表示了這個類具有被Clone的能力,如果沒有實現此接口,而去使用clone(),就會拋出CloneNotSupportedException異常。
2、重寫Object類中的clone方法。Java中,所有類的父類都是Object類,Object類中有一個clone方法,作用是返回對象的一個拷貝,但是其作用域protected類型的,一般的類無法調用,因此,Prototype類需要將clone方法的作用域修改爲public類型。
下面就以羊來爲原型克隆多利
代碼實現
package cn.wong.pattern.prototype;
import java.util.Date;
public class Sheep implements Cloneable {
private String name;
private Date birthDay;
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
public Sheep() {
}
public Sheep(String name, Date birthDay) {
this.name = name;
this.birthDay = birthDay;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Date getBirthDay() {
return birthDay;
}
public void setBirthDay(Date birthDay) {
this.birthDay = birthDay;
}
}
package cn.wong.pattern.prototype;
import java.util.Date;
public class Client {
public static void main(String[] args) throws CloneNotSupportedException {
Sheep s1 = new Sheep("芬蘭母羊",new Date(324324234L));
System.out.println(s1);
System.out.println(s1.getName());
System.out.println(s1.getBirthDay());
System.out.println("---------進行clone----------");
Sheep s2 = (Sheep)s1.clone();
System.out.println(s2);
System.out.println(s2.getName());
System.out.println(s2.getBirthDay());
}
}
結果:
cn.wong.pattern.prototype.Sheep@4633c1aa
芬蘭母羊
Mon Jan 05 02:05:24 CST 1970
---------進行clone----------
cn.wong.pattern.prototype.Sheep@28a50395
芬蘭母羊
Mon Jan 05 02:05:24 CST 1970
從結果可以看出拷貝出來的是一個新的對象,並和原始對象具有相同的屬性值
使用原型模式創建對象比直接new一個對象在性能上要好很多,因爲Object類的clone方法是一個本地方法,它直接操作內存中的二進制流,特別是複製大對象時,性能的差別非常明顯。
protected native Object clone() throws CloneNotSupportedException;
使用原型模式的注意事項
1. 使用原型模式不會調用類的構造方法,因爲它是直接在內存中進行復制的。
2. 深拷貝和淺拷貝
四、淺拷貝和深拷貝
Object類的clone方法只會拷貝對象中的8中基本數據類型,對於數組、日期、容器對象、引用對象等都不會拷貝,這就是淺拷貝。如果要實現深拷貝,必須將原型模式中的數組、容器對象、引用對象等另行拷貝
淺拷貝:
package cn.wong.pattern.prototype;
import java.util.Date;
public class Sheep implements Cloneable {
private String name;
private Date birthDay;
@Override
public Object clone() throws CloneNotSupportedException {
Object obj = super.clone();
/*Sheep s = (Sheep)obj;
s.birthDay=(Date) this.birthDay.clone();*/
return obj;
}
public Sheep() {
}
public Sheep(String name, Date birthDay) {
this.name = name;
this.birthDay = birthDay;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Date getBirthDay() {
return birthDay;
}
public void setBirthDay(Date birthDay) {
this.birthDay = birthDay;
}
}
package cn.wong.pattern.prototype;
import java.util.Date;
public class Client {
public static void main(String[] args) throws CloneNotSupportedException {
Date date = new Date(324324234L);
Sheep s1 = new Sheep("芬蘭母羊",date);
System.out.println("---------打印s1的信息----------");
System.out.println(s1);
System.out.println(s1.getName());
System.out.println(s1.getBirthDay());
//進行復制
Sheep s2 = (Sheep)s1.clone();
//修改s1所指向的時間
date.setTime(23432454354L);
System.out.println("\n---------再次打印s1的信息----------");
System.out.println(s1.getName());
System.out.println(s1.getBirthDay());
System.out.println("\n---------打印s2的信息----------");
System.out.println(s2);
System.out.println(s2.getName());
System.out.println(s2.getBirthDay());
}
}
結果:
---------打印s1的信息----------
cn.wong.pattern.prototype.Sheep@5df1cc1a
芬蘭母羊
Mon Jan 05 02:05:24 CST 1970
---------再次打印s1的信息----------
芬蘭母羊
Tue Sep 29 13:00:54 CST 1970
---------打印s2的信息----------
cn.wong.pattern.prototype.Sheep@7a0ec850
芬蘭母羊
Tue Sep 29 13:00:54 CST 1970
發現s2的信息是改變時間後的,我們知道,clone是在修改時間前進行。所以由此我們可以知道引用類型對象不會進行拷貝,s1、s2兩個對象同時都是指向同一個Date,這就是淺拷貝。
深拷貝:
如果要實現深拷貝,必須將引用對象另行拷貝。而對於java的大部分的類都實現了Cloneable接口,所以深拷貝並不困難。
修改Sheep中clone方法
@Override
public Object clone() throws CloneNotSupportedException {
Object obj = super.clone();
Sheep s = (Sheep)obj;
s.birthDay=(Date) this.birthDay.clone();
return obj;
}
測試不變
package cn.wong.pattern.prototype;
import java.util.Date;
public class Client {
public static void main(String[] args) throws CloneNotSupportedException {
Date date = new Date(324324234L);
Sheep s1 = new Sheep("芬蘭母羊",date);
System.out.println("---------打印s1的信息----------");
System.out.println(s1);
System.out.println(s1.getName());
System.out.println(s1.getBirthDay());
//進行復制
Sheep s2 = (Sheep)s1.clone();
//修改s1所指向的時間
date.setTime(23432454354L);
System.out.println("\n---------再次打印s1的信息----------");
System.out.println(s1.getName());
System.out.println(s1.getBirthDay());
System.out.println("\n---------打印s2的信息----------");
System.out.println(s2);
System.out.println(s2.getName());
System.out.println(s2.getBirthDay());
}
}
結果
---------打印s1的信息----------
cn.wong.pattern.prototype.Sheep@2d8eef25
芬蘭母羊
Mon Jan 05 02:05:24 CST 1970
---------再次打印s1的信息----------
芬蘭母羊
Tue Sep 29 13:00:54 CST 1970
---------打印s2的信息----------
cn.wong.pattern.prototype.Sheep@60813aca
芬蘭母羊
Mon Jan 05 02:05:24 CST 1970