來源:http://www.bjsxt.com/
一、S03E233_01【GOF23設計模式】_原型模式、prototype、淺複製、深複製、Cloneable接口
淺複製
package com.test.prototype;
import java.util.Date;
/**
* 淺複製
*/
public class Sheep implements Cloneable{//Cloneable爲標記接口
private String sname;
private Date birthday;
@Override
protected Object clone() throws CloneNotSupportedException {
Object obj = super.clone();//直接調用object對象的clone()方法
return obj;
}
public Sheep() {
}
public Sheep(String sname, Date birthday) {
super();
this.sname = sname;
this.birthday = birthday;
}
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;
}
}
package com.test.prototype;
import java.util.Date;
/**
* 測試原型模式(淺複製)
*/
public class Client {
public static void main(String[] args) throws Exception {
Date date = new Date(3333332323L);
Sheep s1 = new Sheep("少利", date);
Sheep s2 = (Sheep) s1.clone();
System.out.println(s1);
System.out.println(s1.getSname());
System.out.println(s1.getBirthday());
date.setTime(332324355555555L);//淺複製:s1和s2指向同一date對象的地址,一改全改
System.out.println(s1.getBirthday());//s1.getBirthday() == s2.getBirthday()
s2.setSname("多利");
System.out.println(s2);
System.out.println(s2.getSname());
System.out.println(s2.getBirthday());
}
}
控制檯輸出:s1修改時間後,s2的也跟着改(Fri Dec 10 00:59:15 CST 12500)
com.test.prototype.Sheep@1db9742
少利
Sun Feb 08 21:55:32 CST 1970
Fri Dec 10 00:59:15 CST 12500
com.test.prototype.Sheep@647e05
多利
Fri Dec 10 00:59:15 CST 12500
深複製
package com.test.prototype;
import java.util.Date;
/**
* 深複製
*/
public class Sheep2 implements Cloneable{//Cloneable爲標記接口
private String sname;
private Date birthday;
@Override
protected Object clone() throws CloneNotSupportedException {
Object obj = super.clone();//直接調用object對象的clone()方法
//添加如下代碼實現深複製(Deep Clone)
Sheep2 s = (Sheep2) obj;
s.birthday = (Date) this.birthday.clone();//屬性克隆!
return obj;
}
public Sheep2() {
}
public Sheep2(String sname, Date birthday) {
super();
this.sname = sname;
this.birthday = birthday;
}
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;
}
}
package com.test.prototype;
import java.util.Date;
/**
* 測試原型模式(深複製)
*/
public class Client2 {
public static void main(String[] args) throws Exception {
Date date = new Date(3333332323L);
Sheep2 s1 = new Sheep2("少利", date);
Sheep2 s2 = (Sheep2) s1.clone();
System.out.println(s1);
System.out.println(s1.getSname());
System.out.println(s1.getBirthday());
date.setTime(332324355555555L);//淺複製:s1和s2指向同一date對象的地址,一改全改
System.out.println(s1.getBirthday());//s1.getBirthday() == s2.getBirthday()
s2.setSname("多利");
System.out.println(s2);
System.out.println(s2.getSname());
System.out.println(s2.getBirthday());
}
}
控制檯輸出:s1修改時間後,s2還是最初的(Sun Feb 08 21:55:32 CST 1970)
com.test.prototype.Sheep2@1db9742
少利
Sun Feb 08 21:55:32 CST 1970
Fri Dec 10 00:59:15 CST 12500
com.test.prototype.Sheep2@647e05
多利
Sun Feb 08 21:55:32 CST 1970
二、S03E234_01【GOF23設計模式】_原型模式、反序列化實現深複製、效率對比、創建型模式總結
利用序列化和反序列化技術實現深複製
package com.test.prototype;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.Date;
/**
* 原型模式(使用序列化和反序列化的方式實現深複製)
*/
public class Client3 {
public static void main(String[] args) throws Exception {
Date date = new Date(3333332323L);
Sheep s1 = new Sheep("少利", date);
System.out.println(s1);
System.out.println(s1.getSname());
System.out.println(s1.getBirthday());
// Sheep s2 = (Sheep) s1.clone();
//使用序列化和反序列化實現深複製
//序列化
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(s1);
byte[] bytes = bos.toByteArray();
//反序列化
ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(bis);
Sheep s2 = (Sheep) ois.readObject();//深複製的對象
System.out.println("修改原型對象的屬性值");
date.setTime(332324355555555L);
System.out.println(s1.getBirthday());
s2.setSname("多利");
System.out.println(s2);
System.out.println(s2.getSname());
System.out.println(s2.getBirthday());
}
}
短時間大量創建對象時,原型模式和普通new方式效率測試:
package com.test.prototype;
/**
* 測試普通new方式創建對象和clone方式創建對象的效率差異!
* 如果需要短時間創建大量對象,並且new的過程比較耗時,則可以考慮使用原型模式!
*/
public class Client4 {
public static void testNew(int size){
long start = System.currentTimeMillis();
for (int i = 0; i < size; i++) {
Laptop t = new Laptop();
}
long end = System.currentTimeMillis();
System.out.println("new的方式創建耗時:" + (end - start));
}
public static void testClone(int size) throws CloneNotSupportedException{
long start = System.currentTimeMillis();
Laptop t = new Laptop();
for (int i = 0; i < size; i++) {
Laptop temp = (Laptop) t.clone();
}
long end = System.currentTimeMillis();
System.out.println("clone的方式創建耗時:" + (end - start));
}
public static void main(String[] args) throws Exception {
testNew(1000);
testClone(1000);
}
}
class Laptop implements Cloneable{//筆記本電腦
public Laptop(){
try{
Thread.sleep(10);//模擬創建對象耗時的過程!
}catch(InterruptedException e){
e.printStackTrace();
}
}
@Override
protected Object clone() throws CloneNotSupportedException {
Object obj = super.clone();//直接調用object對象的clone()方法
return obj;
}
}
控制檯輸出:
new的方式創建耗時:10168
clone的方式創建耗時:10
開發中的應用場景:
原型模式很少單獨出現,一般和工廠模式一起出現,通過clone的方法創建一個對象,然後由工廠方法提供給調用者。
spring中bean的創建實際就是兩種:單例模式和原型模式(原型模式需要和工廠模式搭配起來)。
創建型模式的總結: