java語言實現(xiàn)創(chuàng)建型設(shè)計模式―原型模式(Prototype)
來源:程序員人生 發(fā)布時間:2015-05-06 08:47:40 閱讀次數(shù):3294次
1、描寫
原型模式是通過1個原型對象來標(biāo)明要創(chuàng)建的對象的類型,然后用復(fù)制這個原型對象的方法來拷貝創(chuàng)建更多的同類型對象。例如我們在程序的動態(tài)運行進程中有了1個對象,這個對象中包括了1系列的有效數(shù)據(jù),我們此時需要1個和該對象完全相同的新對象,并且在拷貝以后,新舊對象之間沒有任何聯(lián)系,對任何1個對象的更改都不影響另外一個對象。
在java中所有類都默許繼承自java.lang.Object類,在這個Object類中有1個clone()方法,該方法將返回Object對象的1個拷貝。
我們讓需要被拷貝的類實現(xiàn) Cloneable
接口,該接口用來唆使Object.clone()方法可以合法地對該類實例進行按字段復(fù)制。如果在沒有實現(xiàn)Cloneable
接口的實例上調(diào)用 Object 的 clone 方法,則會致使拋出
CloneNotSupportedException
異常。
注意:Cloneable接口是1個標(biāo)記接口,該接口中沒有任何別的方法,只是作為標(biāo)記來標(biāo)明這個類可以合法的使用Object類的clone()方法來產(chǎn)生該實例的1個副本。
除Cloneable接口是標(biāo)記接口以外還有Serializable接口(用于類啟用其序列化功能,未實現(xiàn)此接口的類將沒法使其任何狀態(tài)序列化或反序列化)、RandomAccess接口(List
實現(xiàn)中所使用的標(biāo)記接口,用來表明其支持快速(通常是固定時間)隨機訪問,從而在將其利用到隨機或連續(xù)訪問列表時能提供良好的性能)、Remote接口(Remote
接口用于標(biāo)識其方法可以從非本地虛擬機上調(diào)用的接口。任何遠程對象都必須直接或間接實現(xiàn)此接口。只有在“遠程接口(擴大java.rmi.Remote
的接口)中指定的這些方法才可遠程使用,實現(xiàn)類可以實現(xiàn)任意數(shù)量的遠程接口,并且可以擴大其他遠程實現(xiàn)類。RMI
提供1些遠程對象實現(xiàn)可以擴大的有用類,這些類便于遠程對象創(chuàng)建)。
2、原型設(shè)計模式的優(yōu)缺點
優(yōu)點:在原型模式中,可以動態(tài)地添加產(chǎn)品類,而且不會對整天結(jié)構(gòu)產(chǎn)生影響,只是復(fù)制了1個對象而已。
缺點:由于原型模式要讓每一個類實現(xiàn)Cloneable
接口,并重寫Object類中的clone()方法,而且原型模式在實現(xiàn)深拷貝的時候需要補充更多的代碼,這無疑增加了1定的代碼量。
3、源代碼
3.1 淺拷貝:如果待拷貝的對象中存在對象類型和援用類型,那末只拷貝對象和援用類型的地址,而是真正拷貝對象和援用中的數(shù)據(jù)。
package tong.day5_1.dogCase;
import java.util.ArrayList;
/**
* DogClone實現(xiàn)了Cloneable接口,重寫clone()方法,調(diào)用父類的clone()拷貝1個對象并返回,Dog類并沒有clone()方法,這是淺拷貝的模式。
* 淺拷貝:基本數(shù)據(jù)類型確切另外拷貝了1個副本,但是對對象類型和援用類型則只拷貝對象或援用的地址,
* 致使拷貝的對象中的對象類型的援用指向同1個對象,只要有1個修改了,就會影響另外一個對象中的數(shù)據(jù)。
* @author tong
*
*/
public class ShallowClone {
public static void main(String[] args) {
//拷貝之前數(shù)據(jù)的值
DogClone dogClone = new DogClone();
System.out.println("原來的dogClone.basicCount="+dogClone.basicCount);
System.out.println("原來的dogClone.dog="+dogClone.dog);
System.out.println("原來的dogClone.arraylist="+dogClone.arrayList);
DogClone dogClone2 = (DogClone) dogClone.clone();
System.out.println("-----------------------");
//對拷貝的對象中的對象類型和援用類型的數(shù)據(jù)進行變更,則會影響另外一個對象的數(shù)據(jù);基本類型是進行值拷貝所以產(chǎn)生另外一個副本,對原數(shù)據(jù)不會有影響
dogClone2.basicCount = 2;
Dog dog = dogClone2.dog;
dog.changeCount();
dogClone2.arrayList.add("java");
//原對象中的基本數(shù)據(jù)類型的值不變
System.out.println("后來的dogClone.basicCount="+dogClone.basicCount);
System.out.println("后來的dogClone.dog="+dogClone.dog);
System.out.println("后來的dogClone.arrayList="+dogClone.arrayList);
System.out.println("dogClone2.basicCount="+dogClone2.basicCount);
System.out.println("dogClone2.dog="+dogClone2.dog);
System.out.println("dogClone2.arrayList="+dogClone2.arrayList);
}
}
class Dog{
public int legCount;
public Dog(int legCount) {
this.legCount = legCount;
}
public void changeCount() {
this.legCount +=5;
}
//重寫Dog類的toString()方法,在輸出dog對象時調(diào)用該方法
@Override
public String toString() {
return Integer.toString(legCount);
}
}
//DogClone實現(xiàn)了Cloneable接口,只要重寫Object中的clone()便可根據(jù)自己的需要拷貝對象
class DogClone implements Cloneable{
//基本數(shù)據(jù)類型拷貝時會直接拷貝數(shù)據(jù)值的1個副本,也就是說拷貝后產(chǎn)生的legCount數(shù)值和原來被拷貝的值沒有任何關(guān)系
public int basicCount;
//Dog對象類型,在使用淺拷貝的時候,拷貝的是棧中對象的地址,而不是對象地址所指向的堆內(nèi)存的真實數(shù)據(jù)
public Dog dog = new Dog(5);
//ArrayList援用類型,在淺拷貝時,只拷貝援用的地址,而不是拷貝援用所指向的堆內(nèi)存中的字符串
public ArrayList<String> arrayList = new ArrayList<String>();
public DogClone() {
basicCount = 4;
arrayList.add("hello");
arrayList.add("world");
}
//重寫了clone()返回1個DogClone類的副本對象
@Override
protected Object clone(){
DogClone dogClone = null;
try {
dogClone = (DogClone) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return dogClone;
}
}
運行結(jié)果:

3.2 深拷貝:DogClone實現(xiàn)了Cloneable接口,重寫clone()方法,調(diào)用父類的clone()拷貝1個對象,并顯式調(diào)用dog對象和arrayList對象的拷貝方法返回該類對象,這樣拷貝產(chǎn)生的對象和原來的對象就互不干擾,相互獨立。
package tong.day5_1.deepClone;
import java.util.ArrayList;
/**
* DogClone實現(xiàn)了Cloneable接口,重寫clone()方法,調(diào)用父類的clone()拷貝1個對象,并顯式調(diào)用dog對象和arrayList對象的拷貝方法返回該類對象,這是深拷貝的模式。
* 深拷貝:基本數(shù)據(jù)類型確切另外拷貝了1個副本,但是對對象類型和援用類型則默許的是只拷貝對象或援用的地址,
* 如果想要使這兩種類型也拷貝對象和援用中的數(shù)據(jù),那末就需要在重寫的clone()方法中顯式地調(diào)用該對象或援用類型的clone()方法。
* 所以我們需要讓Dog類實現(xiàn)Cloneable接口使其具有拷貝能力,ArrayList間接繼承了Object接口,本身就有clone()方法。
* @author tong
*
*/
public class DeepClone {
public static void main(String[] args) {
// 拷貝之前數(shù)據(jù)的值
DogClone dogClone = new DogClone();
System.out.println("原來的dogClone.basicCount=" + dogClone.basicCount);
System.out.println("原來的dogClone.dog=" + dogClone.dog);
System.out.println("原來的dogClone.arraylist=" + dogClone.arrayList);
DogClone dogClone2 = (DogClone) dogClone.clone();
System.out.println("-----------------------");
// 這里進行的是深拷貝,對拷貝的對象中的對象類型和援用類型的數(shù)據(jù)進行變更,不會影響另外一個對象的數(shù)據(jù);基本類型是進行值拷貝所以產(chǎn)生另外一個副本,對原數(shù)據(jù)也不會有影響
dogClone2.basicCount = 2;
Dog dog = dogClone2.dog;
dog.changeCount();
dogClone2.arrayList.add("java");
// 原對象中所有數(shù)據(jù)的值都不變
System.out.println("后來的dogClone.basicCount=" + dogClone.basicCount);
System.out.println("后來的dogClone.dog=" + dogClone.dog);
System.out.println("后來的dogClone.arrayList=" + dogClone.arrayList);
System.out.println("dogClone2.basicCount=" + dogClone2.basicCount);
System.out.println("dogClone2.dog=" + dogClone2.dog);
System.out.println("dogClone2.arrayList=" + dogClone2.arrayList);
}
}
//為了實現(xiàn)深拷貝,我們讓Dog類實現(xiàn)Cloneable接口并重寫該接口中的clone()方法
class Dog implements Cloneable {
public int legCount;
public Dog(int legCount) {
this.legCount = legCount;
}
public void changeCount() {
this.legCount += 5;
}
// 重寫Dog類的toString()方法,在輸出dog對象時調(diào)用該方法
@Override
public String toString() {
return Integer.toString(legCount);
}
//重寫clone()方法,使其dog對象具有自我復(fù)制的能力
@Override
protected Object clone() {
Dog dog = null;
try {
dog = (Dog) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return dog;
}
}
////為了進行DogClone對象的拷貝,我們讓DogClone類實現(xiàn)Cloneable接口并重寫重寫Object中的clone()方法
class DogClone implements Cloneable {
// 基本數(shù)據(jù)類型拷貝時會直接拷貝數(shù)據(jù)值的1個副本,也就是說拷貝后產(chǎn)生的legCount數(shù)值和原來被拷貝的值沒有任何關(guān)系
public int basicCount;
// Dog對象類型,在使用淺拷貝的時候,拷貝的是棧中對象的地址,而不是對象地址所指向的堆內(nèi)存的真實數(shù)據(jù)
public Dog dog = new Dog(5);
// ArrayList援用類型,在淺拷貝時,只拷貝援用的地址,而不是拷貝援用所指向的堆內(nèi)存中的字符串
public ArrayList<String> arrayList = new ArrayList<String>();
public DogClone() {
basicCount = 4;
arrayList.add("hello");
arrayList.add("world");
}
//重寫了clone()返回1個DogClone類的副本對象
@Override
protected Object clone() {
DogClone dogClone = null;
try {
dogClone = (DogClone) super.clone();
} catch (CloneNotSupportedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//顯式調(diào)用dog對象的clone()返回1個dog對象的副本
dogClone.dog = (Dog) dog.clone();
//顯式調(diào)用arrayList對象的clone()返回1個arrayList對象的副本
dogClone.arrayList = (ArrayList<String>) arrayList.clone();
return dogClone;
}
}
運行結(jié)果:

生活不易,碼農(nóng)辛苦
如果您覺得本網(wǎng)站對您的學(xué)習(xí)有所幫助,可以手機掃描二維碼進行捐贈