Java設(shè)計模式中的原型模式講解
介紹
原型模式
在Java中,原型模式是一種創(chuàng)建型設(shè)計模式,它允許通過復(fù)制一個現(xiàn)有對象來創(chuàng)建一個新對象,而不是通過創(chuàng)建新的對象來初始化一個對象,原型模式是一種基于克隆的設(shè)計模式,通過復(fù)制現(xiàn)有對象的數(shù)據(jù)來創(chuàng)建新的對象.
原型模式需要實(shí)現(xiàn)Cloneable接口并重寫Object類中的clone()方法,在重謝clone()方法時,需要調(diào)用super.clone()方法來創(chuàng)建一個新的對象,并復(fù)制原始對象中的所有屬性.默認(rèn)情況下,Java中的Object類提供的clone()方法會執(zhí)行淺拷貝,如果原始對象中包含引用類型的成員變量,則需要進(jìn)行深拷貝操作,以確保新對象中所有成員變量都是獨(dú)立的.
深拷貝與淺拷貝
淺拷貝(Shallow Copy)會創(chuàng)建一個新的對象,該對象具有與原始對象相同的屬性值.但是,如果原始對象包含對其他對象的引用,則新對象也將包含對相同對象的引用.換句話說,新對象僅僅是原始對象的一個副本,而不是獨(dú)立的對象.
深拷貝(Deep Copy)則是創(chuàng)建一個新的對象,該對象具有與原始對象相同的屬性值,但是它會遞歸的復(fù)制對象圖中所有的對象,而不是只復(fù)制引用.換句話說,深拷貝會創(chuàng)建一個完全獨(dú)立的新對象,該對象與原始對象沒有任何關(guān)聯(lián).
區(qū)別:
- 對于基本數(shù)據(jù)類型,淺拷貝和深拷貝沒有區(qū)別,因?yàn)榛緮?shù)據(jù)類型在內(nèi)存中儲存為值.但是對于引用類型,淺拷貝和深拷貝會有不同的行為.淺拷貝只復(fù)制對象本身以及其中的基本數(shù)據(jù)類型成員,而不會復(fù)制引用類型成員.因此,如果原始對象中包含引用類型成員,淺拷貝得到的對象中的引用類型成員與原始對象中的相同,即兩者指向同一塊內(nèi)存地址.而深拷貝則會遞歸的復(fù)制所有的引用類型成員,因此得到的對象中的引用類型成員與原始對象中的不同,即兩者指向不同的內(nèi)存地址.
- 淺拷貝速度相對較快,因?yàn)樗粡?fù)制了對象本身以及其中的基本數(shù)據(jù)類型成員.而深拷貝速度相對較慢,因?yàn)樗枰f歸的復(fù)制所有引用類型成員.
應(yīng)用場景:
- 淺拷貝通常用于快速創(chuàng)建對象副本,且原始對象中不包含引用類型成員的情況下,可以使用淺拷貝.比如,當(dāng)需要多個對象共享某些狀態(tài)時,可以使用淺拷貝來快速創(chuàng)建副本
- 深拷貝通常用于創(chuàng)建完全獨(dú)立的對象,且原始對象中包含引用類型成員的情況下,可以使用深拷貝
淺拷貝示例代碼
@Data public class Person implements Cloneable{ private String name; private int age; private Address address; public Person(String name, int age, Address address) { this.name = name; this.age = age; this.address = address; } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } } @Data public class Address { private String city; private String street; public Address(String city, String street) { this.city = city; this.street = street; } }
測試淺拷貝
package com.fanqiechaodan.prototype.copy.shollow; import com.alibaba.fastjson.JSON; /** * @Classname Demo * @Description 淺拷貝 */ public class Demo { public static void main(String[] args) throws CloneNotSupportedException { Person person1 = new Person("張三", 18, new Address("上海", "南京路")); Person person2 = (Person) person1.clone(); System.out.println(JSON.toJSONString(person1)); System.out.println(JSON.toJSONString(person2)); System.out.println("淺拷貝后:"); person1.getAddress().setCity("南京"); System.out.println(JSON.toJSONString(person1)); System.out.println(JSON.toJSONString(person2)); } }
深拷貝示例代碼
@Data public class Person implements Serializable { private String name; private int age; private Address address; public Person(String name, int age, Address address) { this.name = name; this.age = age; this.address = address; } @Override protected Object clone() { try { ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(this); ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bis); return ois.readObject(); } catch (IOException | ClassNotFoundException e) { e.printStackTrace(); } return null; } } @Data public class Address implements Serializable { private String city; private String street; public Address(String city, String street) { this.city = city; this.street = street; } }
測試深拷貝
package com.fanqiechaodan.prototype.copy.deep; import com.alibaba.fastjson.JSON; import org.springframework.util.SerializationUtils; import java.io.IOException; /** * @Classname Demo * @Description 深拷貝 */ public class Demo { public static void main(String[] args) throws IOException, ClassNotFoundException { Person person1 = new Person("張三", 18, new Address("上海", "南京路")); // 重寫clone完成深拷貝 Person person2 = (Person) person1.clone(); // 使用工具類完成深拷貝 Person person3 = (Person) SerializationUtils.deserialize(SerializationUtils.serialize(person1)); System.out.println(JSON.toJSONString(person1)); System.out.println(JSON.toJSONString(person2)); System.out.println(JSON.toJSONString(person3)); System.out.println("深拷貝后:"); person1.getAddress().setCity("南京"); System.out.println(JSON.toJSONString(person1)); System.out.println(JSON.toJSONString(person2)); System.out.println(JSON.toJSONString(person3)); } }
原型模式代碼
原型類代碼
@Data public class Person implements Cloneable{ private String name; private int age; private Address address; public Person(String name, int age, Address address) { this.name = name; this.age = age; this.address = address; } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } } @Data public class Address { private String city; private String street; public Address(String city, String street) { this.city = city; this.street = street; } }
測試
package com.fanqiechaodan.prototype; import com.alibaba.fastjson.JSON; /** * @Classname Demo * @Description */ public class Demo { public static void main(String[] args) throws CloneNotSupportedException { Person person1 = new Person("張三", 18, new Address("北京", "青年路")); Person person2 = (Person) person1.clone(); System.out.println(JSON.toJSONString(person1)); System.out.println(JSON.toJSONString(person2)); } }
需要注意的是,在使用Cloneable接口實(shí)現(xiàn)原型模式時,需要注意以下幾點(diǎn):
- 要使用克隆方法,必須確保該對象實(shí)現(xiàn)了Cloneable接口.否則,在調(diào)用clone方法時會拋出CloneNotSupportedException異常
- 調(diào)用clone方法返回的是一個淺拷貝對象,如果對象包含了引用類型的成員變量,那么這些成員變量依然會被多個對象共享.
- 在實(shí)現(xiàn)clone方法時,需要注意對成員變量的處理,特別是對引用類型的成員變量的處理.如果需要實(shí)現(xiàn)深拷貝,可以通過重寫clone方法來實(shí)現(xiàn).
總結(jié)
優(yōu)點(diǎn):
- 減少了重復(fù)代碼的編寫,避免了創(chuàng)建大量相似對象的開銷,提高了系統(tǒng)的性能.
- 可以動態(tài)的創(chuàng)建對象,而不是靜態(tài)地在代碼中定義,更加靈活.
- 簡化了對象的創(chuàng)建過程,減少了不必要的參數(shù)傳遞.
缺點(diǎn):
- 由于原型模式會復(fù)制對象,可能導(dǎo)致對象狀態(tài)的改變,因此需要謹(jǐn)慎處理.
- 由于原型模式使用了克隆的方式創(chuàng)建對象,可能導(dǎo)致類的層次結(jié)構(gòu)比較復(fù)雜.
應(yīng)用場景:
- 當(dāng)需要創(chuàng)建大量相似的對象時,使用原型模式可以大大減少對象創(chuàng)建的開銷.
- 當(dāng)對象的創(chuàng)建過程比較復(fù)雜,或者對象的狀態(tài)會隨著時間的推移而發(fā)生改變時,可以考慮使用原型模式.
- 當(dāng)需要動態(tài)地創(chuàng)建對象時,可以使用原型模式.例如:在運(yùn)行時動態(tài)創(chuàng)建新對象或者在數(shù)據(jù)庫中讀取對象并創(chuàng)建新對象.
到此這篇關(guān)于Java設(shè)計模式中的原型模式講解的文章就介紹到這了,更多相關(guān)Java原型設(shè)計模式內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Spring注解驅(qū)動之@EventListener注解使用方式
這篇文章主要介紹了Spring注解驅(qū)動之@EventListener注解使用方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-09-09Java實(shí)現(xiàn)excel動態(tài)列導(dǎo)出的示例代碼
這篇文章主要為大家詳細(xì)介紹了如何使用Java實(shí)現(xiàn)excel動態(tài)列導(dǎo)出,文中的示例代碼講解詳細(xì),具有一定的借鑒價值,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-03-03Java?實(shí)戰(zhàn)范例之校園二手市場系統(tǒng)的實(shí)現(xiàn)
讀萬卷書不如行萬里路,只學(xué)書上的理論是遠(yuǎn)遠(yuǎn)不夠的,只有在實(shí)戰(zhàn)中才能獲得能力的提升,本篇文章手把手帶你用java+SSM+mysql+maven+tomcat實(shí)現(xiàn)一個校園二手市場系統(tǒng),大家可以在過程中查缺補(bǔ)漏,提升水平2021-11-11java實(shí)現(xiàn)微信公眾號消息推送的方法詳解
這篇文章主要為大家詳細(xì)介紹了如何利用java實(shí)現(xiàn)微信公眾號消息推送的功能,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2023-10-10MybatisPlus實(shí)現(xiàn)邏輯刪除功能
這篇文章主要介紹了MybatisPlus實(shí)現(xiàn)邏輯刪除功能,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-12-12Java實(shí)現(xiàn)滑動驗(yàn)證碼的示例代碼
這篇文章主要介紹了Java實(shí)現(xiàn)滑動驗(yàn)證碼的示例代碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-01-01Java 將字符串動態(tài)生成字節(jié)碼的實(shí)現(xiàn)方法
本篇文章主要是對Java將字符串動態(tài)生成字節(jié)碼的實(shí)現(xiàn)方法進(jìn)行了介紹,需要的朋友可以過來參考下,希望對大家有所幫助2014-01-01