java設計模式:原始模型模式
什么是原始模型模式
通過給出一個原型對象指明所要創(chuàng)建的對象的類型,然后通過復制這個原型對象來獲取的更多的同類型的對象。
這讓我不由自主的想起克隆技術,還記得克隆羊嗎?我們接下來講的內(nèi)容和克隆羊不能說關系密切,只能說毫無關系。
設計模式和編程語言無關,但是二當家的依然用Java語言去實戰(zhàn)舉例。而且Java有標準的實現(xiàn)原始模型模式的方法。
原始模型模式中的角色
Prototype:抽象類或者一個接口,給出具體模型需要的接口。ConcretePrototype:繼承抽象原型模型角色,被復制的對象。Client:提出復制請求。
抽象原型角色(Prototype)
我們用家庭作業(yè)為抽象原型角色(Prototype)。我們這里的作業(yè)是可以抄的。大家不要學哈。
package com.secondgod.prototype; /** * 作業(yè) * * @author 二當家的白帽子 https://le-yi.blog.csdn.net/ */ public interface IHomework { /** * 抄一份 * @return */ IHomework copy(); /** * 修改所有者 * @param owner */ void setOwner(String owner); }
具體原型角色(ConcretePrototype)
我們用語文作業(yè)作為具體原型角色(ConcretePrototype)。
package com.secondgod.prototype; import java.text.MessageFormat; /** * 語文作業(yè) * * @author 二當家的白帽子 https://le-yi.blog.csdn.net/ */ public class ChineseHomework implements IHomework { /** * 作業(yè)的所有者 */ private String owner; /** * 作業(yè)標題/作業(yè)要求 */ private String title; /** * 作業(yè)內(nèi)容 */ private String content; public ChineseHomework(String owner, String title, String content) { this.owner = owner; this.title = title; this.content = content; } public String getOwner() { return owner; } public void setOwner(String owner) { this.owner = owner; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } public String toString() { return MessageFormat.format("owner:{0},title:{1},content:{2}", owner, title, content); } @Override public IHomework copy() { ChineseHomework homework = new ChineseHomework(this.getOwner(), this.getTitle(), this.getContent()); return homework; } }
客戶端角色(Client)
我們測試一下。
package com.secondgod.prototype; /** * 測試原始模型 * * @author 二當家的白帽子 https://le-yi.blog.csdn.net/ */ public class Test { public static void main(String[] args) { // 老師讓寫作業(yè),大當家按時完成 IHomework homework = new ChineseHomework("大當家的", "作文-最崇拜的人", "不瞞你們說,我最崇拜的是二當家的"); // 二當家的沒按時完成,決定去抄大當家的作業(yè)~ IHomework newHomework = homework.copy(); newHomework.setOwner("二當家的"); System.out.println(homework); System.out.println(newHomework); } }
和我們的預期一致
使用Java內(nèi)置機制實現(xiàn)原始模型模式
在Object類中有這樣一個方法,Java中所有的類都繼承自Object類,也就是說所有的類內(nèi)部都可以復制自己。但是卻不能直接調(diào)用別的類的克隆方法。也就是說有統(tǒng)一的方式,但是默認不可用。
我們改一下語文作業(yè)類,使用clone方法去嘗試,克隆自己。
package com.secondgod.prototype; import java.text.MessageFormat; /** * 語文作業(yè) * * @author 二當家的白帽子 https://le-yi.blog.csdn.net/ */ public class ChineseHomework implements IHomework { /** * 作業(yè)的所有者 */ private String owner; /** * 作業(yè)標題/作業(yè)要求 */ private String title; /** * 作業(yè)內(nèi)容 */ private String content; public ChineseHomework(String owner, String title, String content) { this.owner = owner; this.title = title; this.content = content; } public String getOwner() { return owner; } public void setOwner(String owner) { this.owner = owner; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } public String toString() { return MessageFormat.format("owner:{0},title:{1},content:{2}", owner, title, content); } @Override public IHomework copy() { try { return (ChineseHomework) super.clone(); } catch (CloneNotSupportedException e) { throw new RuntimeException(e); } } }
這時候會報錯,因為我們還少做一件事。我們需要把語文作業(yè)類實現(xiàn)Cloneable接口,然而這個接口里沒有任何抽象方法,僅僅是一個標記接口。這就像注解一樣,就是為了明確聲明可以克隆。
實現(xiàn)接口后,則可以正確運行。
package com.secondgod.prototype; import java.text.MessageFormat; /** * 語文作業(yè) * * @author 二當家的白帽子 https://le-yi.blog.csdn.net/ */ public class ChineseHomework implements IHomework, Cloneable { /** * 作業(yè)的所有者 */ private String owner; /** * 作業(yè)標題/作業(yè)要求 */ private String title; /** * 作業(yè)內(nèi)容 */ private String content; public ChineseHomework(String owner, String title, String content) { this.owner = owner; this.title = title; this.content = content; } public String getOwner() { return owner; } public void setOwner(String owner) { this.owner = owner; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } public String toString() { return MessageFormat.format("owner:{0},title:{1},content:{2}", owner, title, content); } @Override public IHomework copy() { try { return (ChineseHomework) super.clone(); } catch (CloneNotSupportedException e) { throw new RuntimeException(e); } } }
和我們自己實現(xiàn)copy效果一樣。clone是一個native方法,是交給本地實現(xiàn)的,通常是直接內(nèi)存拷貝。
淺拷貝和深拷貝
淺拷貝:創(chuàng)建一個新對象,然后將當前對象的非靜態(tài)字段復制到該新對象,如果字段是值類型的,那么對該字段執(zhí)行復制;如果該字段是引用類型的話,則復制引用但不復制引用的對象。因此,原始對象及其副本引用同一個對象。
深拷貝:創(chuàng)建一個新對象,然后將當前對象的非靜態(tài)字段復制到該新對象,無論該字段是值類型的還是引用類型,都復制獨立的一份。當你修改其中一個對象的任何內(nèi)容時,都不會影響另一個對象的內(nèi)容。
二當家的理解方式是,淺拷貝就是僅拷貝當前對象的內(nèi)容,深拷貝就是遞歸拷貝當前對象和當前對象的引用類型屬性的內(nèi)容,直到全部都是基本數(shù)據(jù)類型的屬性為止。另外,僅僅使用clone方法是淺拷貝。
package com.secondgod.prototype;/** * 測試原始模型 * * @author 二當家的白帽子 https://le-yi.blog.csdn.net/ */public class Test implements Cloneable { private Field field; public Field getField() { return field; } public void setField(Field field) { this.field = field; } public Test clone() throws CloneNotSupportedException { return (Test) super.clone(); } public static void main(String[] args) throws CloneNotSupportedException { Test t = new Test(); t.setField(new Field()); Test cloneT = t.clone(); System.out.println(t == cloneT); System.out.println(t.getField() == cloneT.getField()); }}class Field {}
源對象和克隆出的新對象field屬性值是同一個對象。所以是淺拷貝。
怎么實現(xiàn)深拷貝
讓每個引用類型屬性內(nèi)部都重寫clone() 方法,然后需要對所有引用類型屬性都調(diào)用clone方法。
package com.secondgod.prototype; /** * 測試原始模型 * * @author 二當家的白帽子 https://le-yi.blog.csdn.net/ */ public class Test implements Cloneable { private Field field; public Field getField() { return field; } public void setField(Field field) { this.field = field; } public Test clone() throws CloneNotSupportedException { return (Test) super.clone(); } public static void main(String[] args) throws CloneNotSupportedException { Test t = new Test(); t.setField(new Field()); Test cloneT = t.clone(); System.out.println(t == cloneT); System.out.println(t.getField() == cloneT.getField()); } } class Field { }
這種方式需要遞歸每個引用類型的屬性,要把他們的類都實現(xiàn)深拷貝,只到僅有基本數(shù)據(jù)類型為止。
利用序列化,這是個偷懶的辦法。但是二當家的覺得更安全,如果你確定是要深拷貝,使用該方式可以防止某處漏實現(xiàn)clone方法,而變成不完全的深拷貝。
package com.secondgod.prototype; /** * 測試原始模型 * * @author 二當家的白帽子 https://le-yi.blog.csdn.net/ */ public class Test implements Cloneable { private Field field; public Field getField() { return field; } public void setField(Field field) { this.field = field; } public Test clone() throws CloneNotSupportedException { return (Test) super.clone(); } public Test deepClone() throws CloneNotSupportedException { Test t = new Test(); t.setField(this.getField().deepClone()); return t; } public static void main(String[] args) throws CloneNotSupportedException { Test t = new Test(); t.setField(new Field()); Test cloneT = t.clone(); System.out.println(t == cloneT); System.out.println(t.getField() == cloneT.getField()); Test deepCloneT = t.deepClone(); System.out.println(t == deepCloneT); System.out.println(t.getField() == deepCloneT.getField()); } } class Field implements Cloneable { public Field clone() throws CloneNotSupportedException { return (Field) super.clone(); } public Field deepClone() throws CloneNotSupportedException { // 沒有引用類型屬性 return this.clone(); } }
到底使用淺拷貝還是深拷貝,要根據(jù)實際情況。但是有一點是確定的,深拷貝需要創(chuàng)建更多對象,占用更多內(nèi)存。
總結
本篇文章就到這里了,希望能給你帶來幫助,也希望您能夠多多關注腳本之家的更多內(nèi)容!
相關文章
SpringBoot整合Redis的哨兵模式的實現(xiàn)
Redis提供了哨兵模式來處理主從切換和故障轉移,本文主要介紹了SpringBoot整合Redis的哨兵模式的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2024-08-08以Spring Boot的方式顯示圖片或下載文件到瀏覽器的示例代碼
這篇文章主要介紹了以Spring Boot的方式顯示圖片或下載文件到瀏覽器的示例代碼,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-01-01基于Security實現(xiàn)OIDC單點登錄的詳細流程
本文主要是給大家介紹 OIDC 的核心概念以及如何通過對 Spring Security 的授權碼模式進行擴展來實現(xiàn) OIDC 的單點登錄。對Security實現(xiàn)OIDC單點登錄的詳細過程感興趣的朋友,一起看看吧2021-09-09Java實戰(zhàn)之基于TCP實現(xiàn)簡單聊天程序
這篇文章主要為大家詳細介紹了如何在Java中基于TCP實現(xiàn)簡單聊天程序,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-03-03解決spring boot 1.5.4 配置多數(shù)據(jù)源的問題
下面小編就為大家?guī)硪黄鉀Qspring boot 1.5.4 配置多數(shù)據(jù)源的問題。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-06-06