摘要:但是這種復(fù)制技術(shù)在的世界里早已出現(xiàn),就是原型模式什么是原型模式用原型實(shí)例指定創(chuàng)建對象的種類,并且通過拷貝這些原型創(chuàng)建新的對象類圖原型模式是設(shè)計(jì)模式中最簡單的,沒有之一。
前言
在現(xiàn)實(shí)世界中,我們通常會(huì)感覺到分身乏術(shù)。要是自己有分身那該多好啊,一個(gè)用來工作,一個(gè)用來看電視,一個(gè)用來玩游戲(無意中透露了自己單身狗的身份-。-),其實(shí)就是克隆,這種技術(shù)存在著很大的弊端,所以現(xiàn)在是禁止使用的。但是這種復(fù)制技術(shù)在java的世界里早已出現(xiàn),就是原型模式
什么是原型模式用原型實(shí)例指定創(chuàng)建對象的種類,并且通過拷貝這些原型創(chuàng)建新的對象
uml類圖原型模式是設(shè)計(jì)模式中最簡單的,沒有之一。因?yàn)樗暮诵木褪且粋€(gè)clone方法,通過這個(gè)方法完成對象的克隆。java提供了cloneable接口來標(biāo)示這個(gè)對象是有可能被克隆的,這個(gè)接口只具有標(biāo)記作用,在jvm中只有具有這個(gè)標(biāo)記的對象才有可能被克隆。有可能克隆變成可以被克隆,就需要我們重寫clone方法
淺拷貝public class Person implements Cloneable{ public Person() { System.out.println("構(gòu)造函數(shù)執(zhí)行了"); } private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } @Override protected Person clone() throws CloneNotSupportedException { return (Person) super.clone(); } }
public class Client { public static void main(String[] args) throws CloneNotSupportedException { Person person = new Person(); person.setName("bin"); Person person1=person.clone(); person1.setName("123"); System.out.println(person.getName()+"---"+person1.getName()); } } 測試結(jié)果: 構(gòu)造函數(shù)執(zhí)行了 bin---123
通過以上例子可以得知,實(shí)現(xiàn)cloneable接口,復(fù)寫clone方法,即可對對象進(jìn)行復(fù)制。有一個(gè)問題clone方法是怎么創(chuàng)建對象的?可以看到,構(gòu)造函數(shù)只執(zhí)行了一次,這就說明clone方法是不會(huì)調(diào)用構(gòu)造函數(shù)的,它其實(shí)是內(nèi)存二進(jìn)制流的拷貝,比直接new對象性能要好很多。
標(biāo)題是淺拷貝,那到底什么是淺拷貝呢?先不要著急,我們來改動(dòng)下例子:
public class Person implements Cloneable{ private ListvalueList = new ArrayList<>(); public void setValue(){ valueList.add("1"); } public List getValue(){ return valueList; } @Override protected Person clone() throws CloneNotSupportedException { return (Person) super.clone(); } }
public class Client { public static void main(String[] args) throws CloneNotSupportedException { Person person = new Person(); person.setValue(); Person person1=person.clone(); person1.setValue(); System.out.println(person1.getValue()); } } 測試過程: 構(gòu)造函數(shù)執(zhí)行了 [1, 1]
或許你會(huì)很費(fèi)解明明進(jìn)行了拷貝,應(yīng)該只會(huì)打印一個(gè)“1”啊,,為什么person1.getValue()會(huì)打印出兩個(gè)“1”呢?因?yàn)閖ava做了一個(gè)偷懶的拷貝動(dòng)作,Object提供的clone方法只拷貝本對象,對其引用對象和內(nèi)部數(shù)組都不拷貝,只是將地址拷貝過來用,這種拷貝方式就是淺拷貝。但是String對象例外,因?yàn)閖ava本就希望將String看成基本數(shù)據(jù)類型,它沒有clone方法,并且它的處理機(jī)制非常特殊,通過字符串池在內(nèi)存中創(chuàng)建新的字符串,我們只要把其看待成基本數(shù)據(jù)類型就可以了。
深拷貝當(dāng)拷貝的對象中有引用對象或者數(shù)組時(shí),我們通過淺拷貝獲得復(fù)制對象是不安全的。怎么解決呢?我們可以通過深拷貝來解決這個(gè)問題,下面繼續(xù)改造例子學(xué)習(xí)深拷貝:
public class Person implements Cloneable{ private ArrayListvalueList = new ArrayList<>(); public void setValue(){ valueList.add("1"); } public List getValue(){ return valueList; } @Override protected Person clone() throws CloneNotSupportedException { Person person=(Person) super.clone(); person.valueList= (ArrayList ) this.valueList.clone(); return person; } }
public class Client { public static void main(String[] args) throws CloneNotSupportedException { Person person = new Person(); person.setValue(); Person person1=person.clone(); person1.setValue(); System.out.println(person.getValue()); System.out.println(person1.getValue()); } } 測試結(jié)果: person:[1] person1[1, 1]
通過對引用對象和數(shù)組的進(jìn)行獨(dú)立的拷貝,就完成了深拷貝,每個(gè)person對象都會(huì)有自己的valueList。
clone和final對象的clone和對象內(nèi)的final是互相沖突的,下面我們來看個(gè)圖片:
當(dāng)我們將valueList增加final關(guān)鍵字,對其clone編譯會(huì)報(bào)錯(cuò),解決辦法就是不要加final關(guān)鍵字(感覺像是廢話...)
原型模式和現(xiàn)實(shí)世界中說的克隆基本一樣。原型模式是內(nèi)存二進(jìn)制流的拷貝,比new對象性能高很多,尤其是當(dāng)創(chuàng)建這個(gè)對象需要數(shù)據(jù)庫或者其他硬件資源時(shí)尤為明顯。另外我們需要注意的就是當(dāng)復(fù)制的對象存在引用對象和數(shù)組時(shí),要根據(jù)實(shí)際業(yè)務(wù)選擇深拷貝還是淺拷貝。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://www.ezyhdfw.cn/yun/70834.html
摘要:如果一個(gè)對象的初始化需要很多其他對象的數(shù)據(jù)準(zhǔn)備或其他資源的繁瑣計(jì)算,那么可以使用原型模式。當(dāng)需要一個(gè)對象的大量公共信息,少量字段進(jìn)行個(gè)性化設(shè)置的時(shí)候,也可以使用原型模式拷貝出現(xiàn)有對象的副本進(jìn)行加工處理。 1、什么是原型模式Specify the kinds of objects to create using a prot...
摘要:三種使用構(gòu)造函數(shù)創(chuàng)建對象的方法和的作用都是在某個(gè)特殊對象的作用域中調(diào)用函數(shù)。這種方式還支持向構(gòu)造函數(shù)傳遞參數(shù)。叫法上把函數(shù)叫做構(gòu)造函數(shù),其他無區(qū)別適用情境可以在特殊的情況下用來為對象創(chuàng)建構(gòu)造函數(shù)。 一、工廠模式 工廠模式:使用字面量和object構(gòu)造函數(shù)會(huì)有很多重復(fù)代碼,在此基礎(chǔ)上改進(jìn)showImg(https://segmentfault.com/img/bVbmKxb?w=456&...
摘要:繼續(xù)分享設(shè)計(jì)模式的公開課,這是第四篇?jiǎng)?chuàng)建型模式之原型模式設(shè)計(jì)模式的一般介紹在第一篇文章講了,不了解的可以先看看。設(shè)計(jì)模式的第一部分,創(chuàng)建型模式就總結(jié)完了。下面還有兩部分結(jié)構(gòu)型設(shè)計(jì)模式和行為型設(shè)計(jì)模式稍后繼續(xù)。 繼續(xù)分享設(shè)計(jì)模式的公開課,這是第四篇?jiǎng)?chuàng)建型模式之原型模式 設(shè)計(jì)模式的一般介紹在第一篇文章講了,不了解的可以先看看。 原型模式: 用原型實(shí)例指定創(chuàng)建對象的種類,并且通過拷貝這個(gè)...
摘要:可以用刪除實(shí)例對象中自己添加的屬性可以確定屬性是原型中還是實(shí)例對象中,當(dāng)時(shí)實(shí)例對象中時(shí),返回的是操作符,有兩種使用方式,單獨(dú)使用和循環(huán)中。單獨(dú)使用,通過對象能夠訪問屬性時(shí)返回,無論時(shí)在原型中還是實(shí)例對象中。 原型模式,每個(gè)創(chuàng)建的對象都有一個(gè)prototype屬性,這個(gè)屬性是一個(gè)指針,指向一個(gè)對象,而這個(gè)對象的用途是包含可以由特定類型的所有實(shí)例共享的屬性和方法。 ------------...
摘要:深入系列第十四篇,講解創(chuàng)建對象的各種方式,以及優(yōu)缺點(diǎn)。也就是說打著構(gòu)造函數(shù)的幌子掛羊頭賣狗肉,你看創(chuàng)建的實(shí)例使用都無法指向構(gòu)造函數(shù)這樣方法可以在特殊情況下使用。 JavaScript深入系列第十四篇,講解創(chuàng)建對象的各種方式,以及優(yōu)缺點(diǎn)。 寫在前面 這篇文章講解創(chuàng)建對象的各種方式,以及優(yōu)缺點(diǎn)。 但是注意: 這篇文章更像是筆記,因?yàn)椤禞avaScript高級程序設(shè)計(jì)》寫得真是太好了! 1....
閱讀 2887·2023-04-26 01:47
閱讀 3658·2023-04-25 23:45
閱讀 2563·2021-10-13 09:39
閱讀 663·2021-10-09 09:44
閱讀 1880·2021-09-22 15:59
閱讀 2896·2021-09-13 10:33
閱讀 1846·2021-09-03 10:30
閱讀 705·2019-08-30 15:53