原型模式就是從一個(gè)對(duì)象再創(chuàng)建另外一個(gè)可定制的對(duì)象
返十, 而且不需要知道任何創(chuàng)建的細(xì)節(jié)策肝。
所謂原型模式肛捍, 就是 Java 中的克隆技術(shù)
, 以某個(gè)對(duì)象為原型之众。 復(fù)制出新的對(duì)象拙毫。 顯然新的對(duì)象具備原型對(duì)象的特點(diǎn), 效率高(避免了重新執(zhí)行構(gòu)造過程步驟)
在介紹原型模式之前棺禾,需要介紹淺拷貝和深拷貝的概念
1.淺拷貝和深拷貝的特點(diǎn)
淺拷貝
:
- ①對(duì)于數(shù)據(jù)類型是
基本數(shù)據(jù)類型
的成員變量缀蹄,淺拷貝會(huì)直接進(jìn)行值傳遞
,也就是將該屬性值復(fù)制一份給新的對(duì)象。 - ②對(duì)于數(shù)據(jù)類型是
引用數(shù)據(jù)類型的成員變量
缺前,比如說成員變量是某個(gè)數(shù)組蛀醉、某個(gè)類的對(duì)象等,那么淺拷貝會(huì)進(jìn)行引用傳遞
诡延,也就是只是將該成員變量的引用值(內(nèi)存地址)復(fù)制一份給新的對(duì)象滞欠。因?yàn)閷?shí)際上兩個(gè)對(duì)象的該成員變量都指向同一個(gè)實(shí)例。在這種情況下肆良,在一個(gè)對(duì)象中修改該成員變量會(huì)影響到另一個(gè)對(duì)象的該成員變量值。
深拷貝
:
- ①復(fù)制對(duì)象的所有
基本數(shù)據(jù)類型的成員變量值
- ②為所有引用數(shù)據(jù)類型的成員變量申請(qǐng)存儲(chǔ)空間逸绎,并
復(fù)制每個(gè)引用數(shù)據(jù)類型成員變量所引用的對(duì)象
惹恃,直到該對(duì)象可達(dá)的所有對(duì)象
。也就是說棺牧,對(duì)象進(jìn)行深拷貝要對(duì)整個(gè)對(duì)象圖
進(jìn)行拷貝巫糙!
總結(jié)
:
深拷貝對(duì)引用數(shù)據(jù)類型的成員變量的對(duì)象圖中所有的對(duì)象都開辟了內(nèi)存空間
;而淺拷貝只是傳遞地址指向
颊乘,新的對(duì)象并沒有對(duì)引用數(shù)據(jù)類型創(chuàng)建內(nèi)存空間
2.原型模式的淺拷貝和深拷貝的實(shí)現(xiàn)方式
- 淺拷貝
通過拷貝構(gòu)造方法
實(shí)現(xiàn)淺拷貝
通過重寫clone()方法
進(jìn)行淺拷貝 - 深拷貝
通過重寫clone方法
來實(shí)現(xiàn)深拷貝
通過對(duì)象序列化
實(shí)現(xiàn)深拷貝
接下來直接介紹淺拷貝和深拷貝的具體實(shí)現(xiàn)
在此之前参淹,先給出原型模式的uml圖
3.原型模式的淺拷貝
淺度克隆目標(biāo)的引用對(duì)象
/**
* @Project: spring
* @description: 淺度克隆目標(biāo)的引用對(duì)象
* @author: sunkang
* @create: 2018-09-02 10:48
* @ModificationHistory who when What
**/
public class CloneableTarget {
public String cloneName;
public String cloneClass;
public CloneableTarget( String cloneName,String cloneClass) {
this.cloneName = cloneName;
this.cloneClass = cloneClass;
}
}
淺度克隆的對(duì)象的兩種實(shí)現(xiàn)方式
/**
* @Project: spring
* @description: 克隆對(duì)象的淺拷貝
* 1.通過構(gòu)造方法來實(shí)現(xiàn)淺度拷貝
* 2.通過clone()方法來實(shí)現(xiàn)淺度拷貝
* @author: sunkang
* @create: 2018-09-02 10:47
* @ModificationHistory who when What
**/
public class Prototype implements Cloneable {
public String name ;
//拷貝的引用類型的成員變量
public CloneableTarget cloneableTarget;
public Prototype(){
}
//1.通過構(gòu)造方法來實(shí)現(xiàn)淺度拷貝
public Prototype(Prototype prototype) {
this.name = prototype.name;
this.cloneableTarget = prototype.cloneableTarget;
}
//2.通過clone()方法來實(shí)現(xiàn)淺度拷貝
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
淺克隆的測(cè)試
/**
* @Project: spring
* @description: 淺度克隆對(duì)象的測(cè)試
*
* @author: sunkang
* @create: 2018-09-02 10:51
* @ModificationHistory who when What
**/
public class CloneTest {
public static void main(String[] args) {
Prototype p = new Prototype();
p.name="kang";
p.cloneableTarget = new CloneableTarget("clone","CloneableTarget");
System.out.println("原有的對(duì)象:"+p);
System.out.println("原有的值對(duì)象引用:"+p.name.hashCode());
System.out.println("原有的引用類型對(duì)象:"+p.cloneableTarget);
try {
//方式一 :通過重寫clone()方法進(jìn)行淺拷貝
Prototype clonePrototype = (Prototype) p.clone();
System.out.println("重寫clone()克隆的對(duì)象:"+clonePrototype);
System.out.println("重寫clone()克隆的值對(duì)象引用:"+p.name.hashCode());
System.out.println("重寫clone()克隆的引用類型對(duì)象:"+ clonePrototype.cloneableTarget);
//通過修改引用對(duì)象String類型的值,發(fā)現(xiàn)原有的對(duì)象的值沒有發(fā)生改變乏悄,因?yàn)镾tring對(duì)象是不可變對(duì)象浙值,放在常量池中的,無法修改的
//String 可以比較特殊檩小,可以看做是值傳遞
clonePrototype.name ="sun";
System.out.println("原有對(duì)象的name:"+p.name);
System.out.println("修改過的clone對(duì)象的name:"+clonePrototype.name);
//方式二: 通過拷貝構(gòu)造方法實(shí)現(xiàn)淺拷貝
Prototype constructClone= new Prototype(p);
System.out.println("構(gòu)造方法克隆的對(duì)象:"+constructClone);
System.out.println("構(gòu)造方法克隆的值對(duì)象引用:"+constructClone.name.hashCode());
System.out.println("構(gòu)造方法克隆的引用類型對(duì)象:"+ constructClone.cloneableTarget);
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}
}
測(cè)試結(jié)果 : 可以發(fā)現(xiàn)引用類型的目標(biāo)對(duì)象為同一個(gè)引用开呐,string 對(duì)象可以看做是值傳遞,string對(duì)象是不可變的规求,克隆對(duì)象修改后的值對(duì)原有對(duì)象的值沒有影響
4.原型模式的深拷貝
深度拷貝的目標(biāo)引用對(duì)象
/**
* 深度拷貝的目標(biāo)引用對(duì)象
*/
public class DeepCloneableTarget implements Serializable,Cloneable {
private String cloneName;
private String cloneClass;
public DeepCloneableTarget(String cloneName, String cloneClass) {
this.cloneName = cloneName;
this.cloneClass = cloneClass;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
深度拷貝的實(shí)現(xiàn)拷貝的兩種方式
/**
* @Project: spring
* @description: 深度拷貝的實(shí)現(xiàn)拷貝的兩種方式
* @author: sunkang
* @create: 2018-09-02 11:19
* @ModificationHistory who when What
**/
public class DeepPrototype implements Serializable,Cloneable {
public String name ;
public DeepCloneableTarget deepCloneableTarget;
public DeepPrototype(){
}
//方式1 :通過重寫clone方法來實(shí)現(xiàn)深拷貝 (引用對(duì)象多筐付,這種方法比較繁瑣)
@Override
protected Object clone() throws CloneNotSupportedException {
Object deep = null;
try {
deep = super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
DeepPrototype deepPrototype = (DeepPrototype) deep;
deepPrototype.deepCloneableTarget = (DeepCloneableTarget) deepPrototype.deepCloneableTarget.clone();
return deepPrototype;
}
//方式2: 通過對(duì)象序列化實(shí)現(xiàn)深拷貝 (推薦)
public Object deepClone(){
ByteArrayOutputStream bos = null;
ObjectOutputStream oos = null;
try {
bos = new ByteArrayOutputStream();
oos = new ObjectOutputStream(bos);
oos.writeObject(this);
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
return ois.readObject();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}finally {
if(oos !=null){
try {
oos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(bos !=null){
try {
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
//輸入流關(guān)閉省略
}
return null;
}
}
深度拷貝的測(cè)試
/**
* @Project: spring
* @description: 深度拷貝的測(cè)試
* @author: sunkang
* @create: 2018-09-02 11:38
* @ModificationHistory who when What
**/
public class DeepCloneTest {
public static void main(String[] args) {
DeepPrototype p = new DeepPrototype();
p.name="kang";
p.deepCloneableTarget = new DeepCloneableTarget("clone","CloneableTarget");
System.out.println("原有的對(duì)象:"+p);
System.out.println("原有的值對(duì)象引用:"+p.name.hashCode());
System.out.println("原有的引用類型對(duì)象:"+p.deepCloneableTarget);
try {
//方式一 :通過重寫clone()方法進(jìn)行淺拷貝
DeepPrototype clonePrototype = (DeepPrototype) p.clone();
System.out.println("clone()方法克隆的對(duì)象:"+clonePrototype);
System.out.println("clone()方法克隆的值對(duì)象引用:"+p.name.hashCode());
System.out.println("clone()方法克隆的引用類型對(duì)象:"+ clonePrototype.deepCloneableTarget);
//方式二: 通過對(duì)象序列化實(shí)現(xiàn)深拷貝
DeepPrototype serializableClone= (DeepPrototype) p.deepClone();
System.out.println("序列化方法克隆的對(duì)象:"+serializableClone);
System.out.println("構(gòu)序列化方法克隆的值對(duì)象引用:"+serializableClone.name.hashCode());
System.out.println("序列化方法克隆的引用類型對(duì)象:"+ serializableClone.deepCloneableTarget);
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}
}
測(cè)試結(jié)果 :可以發(fā)現(xiàn)引用類型的成員變量的地址都是不一樣
的了,說明實(shí)現(xiàn)了深度拷貝