原型模式是一種簡單、易使用的創(chuàng)建型設(shè)計(jì)模式,通過給出一個(gè)原型對象來指明所創(chuàng)建的對象的類型,然后用復(fù)制這個(gè)原型對象的辦法創(chuàng)建出更多同類型的對象。原型模式要求對象實(shí)現(xiàn)一個(gè)可以“克隆”自身的接口切蟋,這樣就可以通過復(fù)制一個(gè)實(shí)例對象本身來創(chuàng)建一個(gè)新的實(shí)例。這樣一來榆芦,通過原型實(shí)例創(chuàng)建新的對象柄粹,就不再需要關(guān)心這個(gè)實(shí)例本身的類型,只要實(shí)現(xiàn)了克隆自身的方法匆绣,就可以通過這個(gè)方法來獲取新的對象镰惦,而無須再去通過new來創(chuàng)建。
原型模式的結(jié)構(gòu)圖
原型模式的參與角色:
(1)客戶角色:客戶類提出創(chuàng)建對象的請求犬绒。
(2)抽象原型角色:這是一個(gè)抽象角色旺入,通常由一個(gè)java接口或抽象類實(shí)現(xiàn),具體原型都需要實(shí)現(xiàn)該接口凯力。
(3)具體原型角色:客戶端所需要的被復(fù)制的對象茵瘾。
下面還是通過代碼描述該模式的具體使用:
1、第一個(gè)文件:抽象原型文件Prototype.java
publicabstractclassPrototypeimplementsCloneable{publicObjectclone()throwsCloneNotSupportedException{returnsuper.clone();? ? }}
2咐鹤、第二個(gè)文件:具體原型文件ConcretePrototype1.java
publicclassConcretePrototype1extendsPrototype{publicstaticintclassFlag =1;//克隆自身方法publicObjectclone()throwsCloneNotSupportedException{return(ConcretePrototype1)super.clone();? ? }}
3拗秘、第三個(gè)文件:具體原型文件ConcretePrototype2.java
publicclassConcretePrototype2extendsPrototype{publicstaticintclassFlag =2;//克隆自身方法publicObjectclone()throwsCloneNotSupportedException{return(ConcretePrototype2)super.clone();? ? }}
4、第四個(gè)文件:TestMain.java
publicclassTestMain{publicstaticvoidmain(String[] args)throwsCloneNotSupportedException{? ? ? ? Prototype prototype1 =newConcretePrototype1();? ? ? ? ConcretePrototype1 concretePrototype1 = (ConcretePrototype1) prototype1.clone();? ? ? ? System.out.println(concretePrototype1.classFlag);? ? ? ? Prototype prototype2 =newConcretePrototype2();? ? ? ? ConcretePrototype2 concretePrototype2 = (ConcretePrototype2) prototype2.clone();? ? ? ? System.out.println(concretePrototype2.classFlag);? ? }}
看了以上代碼祈惶,大家可能會覺得原型模式其實(shí)還是挺簡單的雕旨。
我們上面描述的對象創(chuàng)建方法是通過調(diào)用java中的clone方法來復(fù)制對象,我看到網(wǎng)上還有另外一種使用new的方式來創(chuàng)建對象捧请,具體原型的寫法如下所示凡涩。
5、第一個(gè)文件:Prototype.java
publicinterfacePrototype{publicObjectclone();}
6疹蛉、第二個(gè)文件:ConcretePrototype1.java
publicclassConcretePrototype1implementsPrototype{@OverridepublicObjectclone(){// 最簡單的克隆活箕,新建一個(gè)自身對象,由于沒有屬性就不再復(fù)制值了Prototype prototype =newConcretePrototype1();returnprototype;? ? }}
7可款、第三個(gè)文件ConcretePrototype2.java
publicclassConcretePrototype2implementsPrototype{@OverridepublicObjectclone(){//最簡單的克隆育韩,新建一個(gè)自身對象克蚂,由于沒有屬性就不再復(fù)制值了Prototype prototype =newConcretePrototype2();returnprototype;? ? }}
至于以上兩種寫法的區(qū)別就在于一種是直接調(diào)用clone方法實(shí)現(xiàn)淺克隆出一個(gè)對象,第二種是使用new筋讨,創(chuàng)建出一個(gè)完完全全獨(dú)立的新對象埃叭,咱就把它稱作是"深克隆"吧。
至于淺克隆和深克隆的區(qū)別是什么呢悉罕,簡單的說:如果一個(gè)對象中只有基本類型屬性赤屋,那深克隆和淺克隆效果都是一樣的,基本類型數(shù)據(jù)不管是用深克隆還是淺克隆都會被克隆出一份蛮粮,但如果對象中包含引用對象屬性,那淺克隆其實(shí)這是拷貝了一份引用谜慌,而深克隆確實(shí)把整個(gè)引用對象都拷貝了一份然想。
在看了原型模式之后,大家可能會覺得這個(gè)跟工廠模式比較的相似欣范。咱們把工廠模式的結(jié)構(gòu)圖也畫一下变泄,大家對比一下就知道的區(qū)別了。
工廠模式的結(jié)構(gòu)圖
比較明顯原型模式?jīng)]有工廠模式的抽象工廠和具體工廠的實(shí)現(xiàn)恼琼,代碼結(jié)構(gòu)要簡單一些妨蛹,當(dāng)然你也可以把原型模式的抽象原型理解成一種特殊的工廠。
8晴竞、原型模式的優(yōu)點(diǎn):
(1)根據(jù)客戶端要求實(shí)現(xiàn)動態(tài)創(chuàng)建對象蛙卤,客戶端不需要知道對象的創(chuàng)建細(xì)節(jié),便于代碼的維護(hù)和擴(kuò)展噩死。
(2)使用原型模式創(chuàng)建對象比直接new一個(gè)對象在性能上要好的多颤难,因?yàn)镺bject類的clone方法是一個(gè)本地方法,它直接操作內(nèi)存中的二進(jìn)制流已维,特別是復(fù)制大對象時(shí)行嗤,性能的差別非常明顯。所以在需要重復(fù)地創(chuàng)建相似對象時(shí)可以考慮使用原型模式垛耳。比如需要在一個(gè)循環(huán)體內(nèi)創(chuàng)建對象栅屏,假如對象創(chuàng)建過程比較復(fù)雜或者循環(huán)次數(shù)很多的話,使用原型模式不但可以簡化創(chuàng)建過程堂鲜,而且可以使系統(tǒng)的整體性能提高很多栈雳。
(3) 原型模式類似于工廠模式,但它沒有了工廠模式中的抽象工廠和具體工廠的層級關(guān)系缔莲,代碼結(jié)構(gòu)更清晰和簡單甫恩。
9、原型模式的注意事項(xiàng):
(1)使用原型模式復(fù)制對象不會調(diào)用類的構(gòu)造方法酌予。因?yàn)閷ο蟮膹?fù)制是通過調(diào)用Object類的clone方法來完成的磺箕,它直接在內(nèi)存中復(fù)制數(shù)據(jù)奖慌,因此不 會調(diào)用到類的構(gòu)造方法。不但構(gòu)造方法中的代碼不會執(zhí)行松靡,甚至連訪問權(quán)限都對原型模式無效简僧。還記得單例模式嗎?單例模式中雕欺,只要將構(gòu)造方法的訪問權(quán)限設(shè)置為 private型岛马,就可以實(shí)現(xiàn)單例。但是clone方法直接無視構(gòu)造方法的權(quán)限屠列,所以啦逆,單例模式與原型模式是沖突的。
(2)在使用時(shí)要注意深拷貝與淺拷貝的問題笛洛。clone方法只會拷貝對象中的基本的數(shù)據(jù)類型夏志,對于數(shù)組、容器對象苛让、引用對象等都不會拷貝沟蔑,這就是淺拷貝。如果要實(shí)現(xiàn)深拷貝狱杰,必須將原型模式中的數(shù)組瘦材、容器對象、引用對象等另行拷貝仿畸。