網(wǎng)頁瀏覽設(shè)置在哪里打開網(wǎng)頁優(yōu)化
設(shè)計模式之禪之設(shè)計模式-原型模式
一:原型模式的定義
? 用原型實例指定創(chuàng)建對象的種類,并且通過拷貝這些原型創(chuàng)建新的對象。
? 原型模式(Prototype Pattern)的簡單程度僅次于單例模式和迭代器模式。正是由于簡單,使用的場景才非常地多。
? 原型模式的核心是一個clone方法,通過該方法進行對象的拷貝,Java提供了一個Cloneable接口來標(biāo)示這個對象是可拷貝的,為什么說是“標(biāo)示”呢?翻開JDK的幫助看看Cloneable是一個方法都沒有的,這個接口只是一個標(biāo)記作用,在JVM中具有這個標(biāo)記的對象才有可能被拷貝。那怎么才能從“有可能被拷貝”轉(zhuǎn)換為“可以被拷貝”呢?方法是覆蓋clone()方法,是的,你沒有看錯是重寫clone()方法,看看我們上面Mail類中的clone方法.該方法重寫了Object對象的方法
二:原型模式的優(yōu)點
? ● 性能優(yōu)良
? 原型模式是在內(nèi)存二進制流的拷貝,要比直接new一個對象性能好很多,特別是要在一個循環(huán)體內(nèi)產(chǎn)生大量的對象時,原型模式可以更好地體現(xiàn)其優(yōu)點。
? ● 逃避構(gòu)造函數(shù)的約束
? 這既是它的優(yōu)點也是缺點,直接在內(nèi)存中拷貝,構(gòu)造函數(shù)是不會執(zhí)行的(參見13.4節(jié))。優(yōu)點就是減少了約束,缺點也是減少了約束,需要大家在實際應(yīng)用時考慮。
三:原型模式的應(yīng)用場景
? ● 資源優(yōu)化場景
? 類初始化需要消化非常多的資源,這個資源包括數(shù)據(jù)、硬件資源等。
? ● 性能和安全要求的場景
? 通過new產(chǎn)生一個對象需要非常繁瑣的數(shù)據(jù)準備或訪問權(quán)限,則可以使用原型模式。
? ● 一個對象多個修改者的場景
? 一個對象需要提供給其他對象訪問,而且各個調(diào)用者可能都需要修改其值時,可以考慮使用原型模式拷貝多個對象供調(diào)用者使用。
? 在實際項目中,原型模式很少單獨出現(xiàn),一般是和工廠方法模式一起出現(xiàn),通過clone的方法創(chuàng)建一個對象,然后由工廠方法提供給調(diào)用者。原型模式已經(jīng)與Java融為一體,大家可以隨手拿來使用。
四:原型模式的注意事項
? 構(gòu)造函數(shù)不會被執(zhí)行
? 注意淺拷貝。你可能會比較奇怪,為什么在Mail那個類中就可以使用String類型,而不會產(chǎn)生由淺拷貝帶來的問題呢?內(nèi)部的數(shù)組和引用對象才不拷貝,其他的原始類型比如int、long、char等都會被拷貝,但是對于String類型,Java就希望你把它認為是基本類型,它是沒有clone方法的,處理機制也比較特殊,通過字符串池(stringpool)在需要的時候才在內(nèi)存中創(chuàng)建新的字符串,讀者在使用的時候就把String當(dāng)做基本類使用即可。
? 使用原型模式時,引用的成員變量必須滿足兩個條件才不會被拷貝:一是類的成員變量,而不是方法內(nèi)變量;二是必須是一個可變的引用對象,而不是一個原始類型或不可變對象。
? 深拷貝還有一種實現(xiàn)方式就是通過自己寫二進制流來操作對象,然后實現(xiàn)對象的深拷貝,這個大家有時間自己實現(xiàn)一下
? 深拷貝和淺拷貝建議不要混合使用,特別是在涉及類的繼承時,父類有多個引用的情況就非常復(fù)雜,建議的方案是深拷貝和淺拷貝分開實現(xiàn)。
五:clone和fianl兩個冤家
? 你要實現(xiàn)深拷貝的夢想在final關(guān)鍵字的威脅下破滅了,路總是有的,我們來想想怎么修改這個方法:刪除掉final關(guān)鍵字,這是最便捷、安全、快速的方式
? 你要使用clone方法,在類的成員變量上就不要增加final關(guān)鍵字。
六:原型模式最佳實踐
? 可以這樣理解:一個對象的產(chǎn)生可以不由零起步,直接從一個已經(jīng)具備一定雛形的對象克隆,然后再修改為生產(chǎn)需要的對象。也就是說,產(chǎn)生一個人,可以不從1歲長到2歲,再到3歲…也可以直接找一個人,從其身上獲得DNA,然后克隆一個,直接修改一下就是30歲了!我們講的原型模式也就是這樣的功能
七:原型模式例子
【1】原型模式的模板
package com.javagpt.design;import java.util.ArrayList;
import java.util.List;/*** 深層次拷貝* (1)深拷貝還有一種實現(xiàn)方式就是通過自己寫二進制流來操作對象,然后實現(xiàn)對象的深拷貝,這個大家有時間自己實現(xiàn)一下* (2)深拷貝和淺拷貝建議不要混合使用,特別是在涉及類的繼承時,父類有多個引用的情況就非常復(fù)雜,建議的方案是深拷貝和淺拷貝分開實現(xiàn)。** @author javagpt*/
public class Thing2 implements Cloneable {private ArrayList<String> list = new ArrayList<String>();@Overrideprotected Thing2 clone() throws CloneNotSupportedException {Thing2 thing2 = null;thing2 = (Thing2) super.clone();thing2.list = (ArrayList<String>) this.list.clone();return thing2;}public List<String> getList() {return list;}public void setList(String a) {this.list.add(a);}}
【2】淺拷貝
package com.javagpt.design;import java.util.ArrayList;
import java.util.List;/*** 淺拷貝** @author javagpt* (1)JVM做了一個偷懶的拷貝動作,Object類提供的方法clone只是拷貝本對象,其對象內(nèi)部的數(shù)組、引用對象等都不拷貝,還是指向原生對象* 的內(nèi)部元素地址,這種拷貝就叫做淺拷貝* (2)非常不安全*/
public class Thing implements Cloneable {private List<String> list = new ArrayList<String>();@Overrideprotected Thing clone() throws CloneNotSupportedException {Thing thing = null;thing = (Thing) super.clone();return thing;}public List<String> getList() {return list;}public void setList(String a) {this.list.add(a);}}
【3】深拷貝
package com.javagpt.design;import java.util.ArrayList;
import java.util.List;/*** 深層次拷貝* (1)深拷貝還有一種實現(xiàn)方式就是通過自己寫二進制流來操作對象,然后實現(xiàn)對象的深拷貝,這個大家有時間自己實現(xiàn)一下* (2)深拷貝和淺拷貝建議不要混合使用,特別是在涉及類的繼承時,父類有多個引用的情況就非常復(fù)雜,建議的方案是深拷貝和淺拷貝分開實現(xiàn)。** @author javagpt*/
public class Thing2 implements Cloneable {private ArrayList<String> list = new ArrayList<String>();@Overrideprotected Thing2 clone() throws CloneNotSupportedException {Thing2 thing2 = null;thing2 = (Thing2) super.clone();thing2.list = (ArrayList<String>) this.list.clone();return thing2;}public List<String> getList() {return list;}public void setList(String a) {this.list.add(a);}}
【4】客戶端測試
package com.javagpt.design;import java.util.List;public class ClientTest {public static void main(String[] args) throws CloneNotSupportedException {//test01();//test02();test03();}/*** 原型模式:模板測試** @throws CloneNotSupportedException*/public static void test01() throws CloneNotSupportedException {Mail mail = new Mail("javagpt", "go smx", "emailtojavagpt", "javagpt@163.com");//ClientTest.main()com.javagpt.design.Mail@2a5330System.out.println("ClientTest.main()" + mail.toString());Mail mail2 = mail.clone();System.out.println("ClientTest.main()" + mail2.toString());//ClientTest.main()com.javagpt.design.Mail@18872380}/*** 原型模式:淺拷貝** @throws CloneNotSupportedException*/public static void test02() throws CloneNotSupportedException {Thing thing1 = new Thing();thing1.setList("小李");Thing thing2 = thing1.clone();thing1.setList("小張");List<String> t = thing1.getList();List<String> t2 = thing2.getList();for (int i = 0; i < t.size(); i++) {System.out.println("ClientTest.test02(t==>)" + t.get(i));}for (int i = 0; i < t2.size(); i++) {System.out.println("ClientTest.test02(t2==>)" + t2.get(i));}//ClientTest.test02(t==>)小李//ClientTest.test02(t==>)小張//ClientTest.test02(t2==>)小李//ClientTest.test02(t2==>)小張}/*** 原型模式:深拷貝** @throws CloneNotSupportedException*/public static void test03() throws CloneNotSupportedException {Thing2 thing2a = new Thing2();thing2a.setList("小李");Thing2 thing2b = thing2a.clone();thing2a.setList("小張");List<String> t = thing2a.getList();List<String> t2 = thing2b.getList();for (int i = 0; i < t.size(); i++) {System.out.println("ClientTest.test02(t==>)" + t.get(i));}for (int i = 0; i < t2.size(); i++) {System.out.println("ClientTest.test02(t2==>)" + t2.get(i));}//ClientTest.test02(t==>)小李//ClientTest.test02(t==>)小張//ClientTest.test02(t2==>)小李}
}