原型模式:以現有對象爲原型,克隆新的一模一樣的對象。減少通過構造方法新建對象時分配屬性、方法的權限時間。
原型方法實現方式:實現Cloneable接口(標記接口)和Object.clone()方法、序列化實現複製。
一、實現Cloneable接口(標記接口)和Object.clone()方法(在破解單例模式中使用過)
通過java提供的Cloneable接口方式實現原型模式,分爲淺克隆和深克隆。
1.淺克隆
package prototype;
import java.util.Date;
public class Sheep implements Cloneable{
//基本類型
private String name;
//對象
private Date birthday;
/**
* 此方法在object方法中 Cloneable接口是一個空接口 調用的是本地方法
* @return
* @throws CloneNotSupportedException
*/
@Override
protected Object clone() throws CloneNotSupportedException {
Sheep obj = (Sheep) super.clone();
return obj;
}
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 prototype;
import java.util.Date;
public class Client {
public static void main(String[] args) throws CloneNotSupportedException {
Sheep sheep = new Sheep();
sheep.setName("小羊");
sheep.setBirthday(new Date(123213));
Sheep sheep2 = (Sheep) sheep.clone();
Date birthday = sheep.getBirthday();
birthday.setTime(123312323);
sheep.setName("大羊");
System.out.println(sheep.getName());
System.out.println(sheep.getBirthday().toString());
System.out.println(sheep2.getName());
System.out.println(sheep2.getBirthday().toString());
}
}
結果
總結:通過object的clone方法克隆的對象,當對象的屬性爲非基本類型時,克隆對象和被克隆對象中是同一個對象。內存示意圖如下克隆是克隆屬性的值(在java中全是值傳遞,當屬性爲非基本類型時屬性存儲的是 對象內存地址的值)
2.深克隆
爲了解決上一問題,我們需要對象也爲新克隆出來的對象。 那麼我們需要重寫clone方法。
@Override
protected Object clone() throws CloneNotSupportedException {
Sheep obj = (Sheep) super.clone();
obj.birthday = (Date) this.birthday.clone();
return obj;
}
增加了屬性對象的單獨克隆obj.birthday = (Date) this.birthday.clone(); 實現深克隆
二、通過序列化實現深克隆
序列化對象實現Serializable接口 ,其他不用修改
測試代碼
package prototype;
import java.io.*;
import java.util.Date;
public class Client2 {
public static void main(String[] args) throws IOException, ClassNotFoundException {
Sheep sheep = new Sheep();
sheep.setName("小羊");
sheep.setBirthday(new Date(123213));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(sheep);
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
Sheep sheep2 = (Sheep) ois.readObject();
sheep.getBirthday().setTime(11111111);
System.out.println(sheep.getName());
System.out.println(sheep.getBirthday().toString());
System.out.println(sheep2.getName());
System.out.println(sheep2.getBirthday().toString());
}
}
測試結果
三、性能對比,測試代碼都是根據實際使用代碼,如你有差異,請指出共同勉進,謝謝
package prototype;
import java.io.*;
import java.util.Date;
public class Client3 {
static int MAXCYCLIC = 100000;
public static void main(String[] args) throws CloneNotSupportedException, IOException, ClassNotFoundException {
Sheep sheep = new Sheep();
sheep.setName("小羊");
sheep.setBirthday(new Date(123213));
Long start = System.currentTimeMillis();
for(int i=0; i<MAXCYCLIC;i++){
Sheep sheep1 = new Sheep();
sheep.setName("小羊");
sheep.setBirthday(new Date(123213));
}
Long end = System.currentTimeMillis();
System.out.println("構造方法創建對象所需時間"+(end-start));
start = System.currentTimeMillis();
for(int i=0; i<MAXCYCLIC;i++){
Sheep sheep1 = (Sheep) sheep.clone();
}
end = System.currentTimeMillis();
System.out.println("克隆接口方式創建對象所需時間"+(end-start));
start = System.currentTimeMillis();
for(int i=0; i<MAXCYCLIC;i++){
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(sheep);
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
Sheep sheep2 = (Sheep) ois.readObject();
ois.close();
bais.close();
oos.close();
baos.close();
}
end = System.currentTimeMillis();
System.out.println("序列化方式創建對象所需時間"+(end-start));
}
}
測試結果(每次結果根據電腦資源情況 會不一致):序列化方式因爲存在 輸入輸出流的創建和關閉非常耗資源和時間。
總結:接口克隆方式性能高但是我們需要更關注代碼的實現,序列化方式簡單粗暴,但是性能相對低, 看具體情況擇優選擇。