手撕設計模式——克隆對象之原型模式

1.業務需求

? 大家好,我是菠菜啊,前倆天有點忙,今天繼續更新了。今天給大家介紹克隆對象——原型模式。老規矩,在介紹這期之前,我們先來看看這樣的需求:《西游記》中每次孫悟空拔出一撮猴毛吹一下,變出一大批猴子加入戰斗,他到底是怎么變的?如果我們幫他實現這個功能,代碼怎么設計?

在這里插入圖片描述

2.代碼實現

首先先說第一個問題,怎么變的我也不知道。

在這里插入圖片描述

但是第二個問題,可以嘗試一下。

實現初步思路:

? 我們新建一個猴子類,并且實例化多個猴子對象不就行了,太簡單了。

Monkey類:

//猴子
public class Monkey {private String name;private String sex;private int age;private Weapon weapon;public Monkey(String name, String sex, int age, Weapon weapon) {this.name = name;this.sex = sex;this.age = age;this.weapon = weapon;}public Weapon getWeapon() {return weapon;}public void setWeapon(Weapon weapon) {this.weapon = weapon;}@Overridepublic String toString() {return "Monkey{" +"name='" + name + '\'' +", sex='" + sex + '\'' +", age=" + age +", weapon=" + weapon +'}';}
}

Weapon類:

//武器
public class Weapon {private String name;private String color;public Weapon(String name, String color) {this.name = name;this.color = color;}@Overridepublic String toString() {return "Weapon{" +"name='" + name + '\'' +", color='" + color + '\'' +'}';}
}

Client類:

public class Client {public static void main(String[] args) {Weapon weapon=new Weapon("金箍棒","金色");Monkey monkey=new Monkey("孫悟空","公",20,weapon);Weapon weapon2=new Weapon(monkey.getWeapon().getName(),monkey.getWeapon().getColor());Monkey monkey2=new Monkey("猴小弟",monkey.getSex(),monkey.getAge(),weapon2);Weapon weapon3=new Weapon(monkey.getWeapon().getName(),monkey.getWeapon().getColor());Monkey monkey3=new Monkey("猴小小弟",monkey.getSex(),monkey.getAge(),weapon3);System.out.println(monkey);System.out.println(monkey2);System.out.println(monkey3);}
}

思考:上述代碼比較簡單,功能是實現了,但是在克隆猴哥的時候,我們要將新建一個相同類的對象。 然后, 我還要必須遍歷原始對象的所有成員變量, 并將成員變量值復制到新對象中。這也太麻煩了,如果屬性是上千上萬個,那么猴哥還沒變出猴子,師傅就被妖怪給吃了。 而且并非所有對象都能通過這種方式進行復制, 因為有些對象可能擁有私有成員變量, 它們在對象本身以外是不可見的。而且克隆對象,要知道該對象類的所有依賴類才行,這樣設計也太不符合迪米特法則了(詳細見***《設計模式——設計原則介紹》***一文)。

3.方案改進

? Java中提供了一個Cloneable接口,其中有一個clone()方法,我們只要實現這個方法就行了。

? 實現代碼結構圖

在這里插入圖片描述

Monkey接口:

//猴子
public class Monkey implements Cloneable{//......@Overrideprotected Monkey clone() throws CloneNotSupportedException {return (Monkey)super.clone();}}

Client類:

public class Client {public static void main(String[] args) throws CloneNotSupportedException {Weapon weapon=new Weapon("金箍棒","金色");Monkey monkey=new Monkey("孫悟空","公",20,weapon);/* Weapon weapon2=new Weapon(monkey.getWeapon().getName(),monkey.getWeapon().getColor());Monkey monkey2=new Monkey("猴小弟",monkey.getSex(),monkey.getAge(),weapon2);Weapon weapon3=new Weapon(monkey.getWeapon().getName(),monkey.getWeapon().getColor());Monkey monkey3=new Monkey("猴小小弟",monkey.getSex(),monkey.getAge(),weapon3);*/Monkey monkey2=monkey.clone();monkey2.setName("猴小弟");Monkey monkey3=monkey.clone();monkey3.setName("猴小小弟");System.out.println(monkey);System.out.println(monkey2);System.out.println(monkey3);}
}

? 思考:這樣我們就可以快速克隆對象,并且不需要知道對象創建的細節,又大大提高了性能,我們把這種設計模式叫做原型模式(Prototype )。上述代碼還是有問題,可以繼續往下看。

拓展:淺克隆和深克隆

? 我們把上述代碼稍微修改一下,看的就明顯了。

Client修改后:

public class Client {public static void main(String[] args) throws CloneNotSupportedException {Weapon weapon=new Weapon("金箍棒","金色");Monkey monkey=new Monkey("孫悟空","公",20,weapon);Monkey monkey2=monkey.clone();monkey2.setName("猴小弟");Monkey monkey3=monkey.clone();monkey3.setName("猴小小弟");System.out.println("修改武器前:"+monkey);System.out.println("修改武器前:"+monkey2);System.out.println("修改武器前:"+monkey3);//修改各自的武器裝備monkey.getWeapon().setColor("紅色");monkey2.getWeapon().setColor("白色");monkey3.getWeapon().setColor("綠色");System.out.println("++++++修改武器+++++");System.out.println("修改武器后:"+monkey);System.out.println("修改武器后:"+monkey2);System.out.println("修改武器后:"+monkey3);}
}

**預期結果:**猴子們的武器顏色分別是紅白綠。

實際結果:猴子們的武器都被綠了(一不小心開車了)。

在這里插入圖片描述

排查原因發現,super.clone(),如果字段是值類型的,就復制值,如果字段是引用類型的,復制引用而不復制引用的對象(String是特殊的引用對象),因此猴子們引用的武器對象是一個。被復制的對象的所有變量值都含有原來對象相同的值,但是其它對象的引用仍然執行原來的對象,叫做淺克隆**。反之,把引用對象的變量指向復制過的新對象,這種叫做深克隆

我們如果要完成深復制,只需做如下修改:

Weapon類:

//武器
public class Weapon implements Cloneable{//...@Overrideprotected Weapon clone() throws CloneNotSupportedException {return (Weapon)super.clone();}}

Monkey類:

public class Monkey implements Cloneable{//...@Overrideprotected Monkey clone() throws CloneNotSupportedException {Monkey clone= (Monkey)super.clone();clone.weapon=this.weapon.clone();return clone;}}

**思考:**如果要深克隆,必須重寫clone方法,如果克隆對象依賴對象的層級嵌套一多,代碼較復雜。

4.定義和組成結構

? 原型模式(Prototype)從一個對象創建一個可定制的對象,而不需要知道任何創建細節。

? 原型模式包含以下主要角色。

  • 抽象原型類(Prototype):規定了具體原型對象必須實現的接口。
  • 具體原型類(ConcretePrototype):實現抽象原型類的 clone() 方法,它是可被復制的對象。
  • 訪問類(Acess):使用具體原型類中的 clone() 方法來復制新的對象。

在這里插入圖片描述

5.優缺點以及應用場景

優點:

  • 通過克隆一個已有的對象,簡化對象的創建過程,不用關注對象的內部創建細節,符合迪米特法則
  • 流的方式比new一個對象克隆對象效率更高

缺點:

  • 克隆對象類必須要重寫clone方法
  • 如果克隆對象依賴對象的嵌套層級較多,并且要達到深克隆,代碼較復雜
  • clone 方法位于類的內部,當對已有類進行改造的時候,可能需要修改代碼,違背了開閉原則

適用場景:

  • 保存對象的狀態并且對象占用內存較少
  • 對象創建成本高,耗用的資源比較多
  • 對象初始化復雜

你的收藏和點贊就是我最大的創作動力,關注我我會持續輸出更新!

友情提示:請尊重作者勞動成果,如需轉載本博客文章請注明出處!謝謝合作!

【作者:我愛吃菠菜 】
在這里插入圖片描述

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/23836.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/23836.shtml
英文地址,請注明出處:http://en.pswp.cn/web/23836.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

pytorch-nn.Module

目錄 1. nn.Module2. nn.Sequential容器3. 網絡參數parameters4. Modules內部管理5. checkpoint6. train/test狀態切換6. 實現自己的網絡層6.1 實現打平操作6.2 實現自己的線性層 7. 代碼 1. nn.Module 是所有nn.類的父類,其中包括nn.Linear nn.BatchNorm2d nn.Con…

每日一練 - OSPF協議驗證機制

01 真題題目 OSPF 只有在 Hello 報文中有驗證信息,OSPF 支持 MD5 密文驗證. A.正確 B.錯誤 02 真題答案 B 03 答案解析 這個陳述是不完全正確的。首先,OSPF確實使用Hello報文來攜帶認證信息,但這不意味著只有Hello報文包含驗證信息。 OSPF的認證機制可…

政府績效考核第三方評估的含義

政府績效考核第三方評估是指由獨立于政府的外部機構(如專業評估公司、研究機構或非政府組織)對政府部門或其下屬單位的績效進行客觀、公正、系統的評估。其主要目的是通過引入獨立的第三方評估機構,對政府績效進行科學、全面的考核&#xff0…

【AIGC調研系列】Qwen2與llama3對比的優勢

Qwen2與Llama3的對比中,Qwen2展現出了多方面的優勢。首先,從性能角度來看,Qwen2在多個基準測試中表現出色,尤其是在代碼和數學能力上有顯著提升[1][9]。此外,Qwen2還在自然語言理解、知識、多語言等多項能力上均顯著超…

肺結節14問,查出肺結節怎么辦?哪些能用中醫調治消散?快來了解一下吧

近些年,隨著大眾防癌意識的加強,和胸部低劑量CT的普及,肺結節的檢出率也逐年升高,不少患者CT報告上,寫著“肺小結”“肺部磨玻璃結節”的字樣,當你看到這幾個字時,會不會瞬間緊張起來&#xff1…

編程規范-代碼檢測-格式化-規范化提交

適用于vue項目的編程規范 – 在多人開發時統一編程規范至關重要 1、代碼檢測 --Eslint Eslint:一個插件化的 javascript 代碼檢測工具 在 .eslintrc.js 文件中進行配置 // ESLint 配置文件遵循 commonJS 的導出規則,所導出的對象就是 ESLint 的配置對…

簡化電動汽車充電器和光伏逆變器的高壓電流檢測

在任何電氣系統中,電流都是一個至關重要的參數。電動汽車 (EV) 充電系統和太陽能系統都需要檢測電流的大小,以便控制和監測功率轉換、充電和放電。電流傳感器通過監測分流電阻器上的壓降或導體中電流產生的磁場來測量電流。 金屬氧化物半導體場效應晶體…

DBeaver連接MySQL提示“Public Key Retrieval is not allowed“問題的解決方式

問題描述 客戶端root用戶連接數據庫出現出現Public Key Retrieval is not allowed 原因分析: 加上allowPublicKeyRetrievalfalse: 解決方案: allowPublicKeyRetrievaltrue:

Java Web學習筆記14——BOM對象

BOM: 概念:瀏覽器對象模型(Browser Object Model),允許JavaScript與瀏覽器對話,JavaScript將瀏覽器的各個組成部分封裝為對象。 組成: Window:瀏覽器窗口對象 介紹:瀏覽…

opencv銳化卷積核的定義和應用(圖像銳化)。

定義銳化卷積核 卷積核(Kernel)是一個小矩陣,它用于在圖像處理操作中,比如模糊、銳化、邊緣檢測等。卷積核通過卷積操作應用于圖像像素,產生新的圖像。 在銳化操作中,我們通常使用一個 3x3 的卷積核。以下…

注解 - @RestController

注解簡介 在今天的每日一注解中,我們將探討RestController注解。RestController是Spring框架中的一個組合注解,方便創建RESTful Web服務。 注解定義 RestController注解是Controller和ResponseBody注解的組合,用于定義RESTful控制器。以下是…

物聯網(IoT)及物聯網網絡協議面試題及參考答案(2萬字長文)

什么是物聯網(IoT)? 物聯網(Internet of Things,簡稱IoT)是一個由互聯網、傳統電信網、傳感器網絡等多種網絡組成的網絡概念。它允許物體與物體、物體與人、人與人之間通過智能傳感器、軟件和網絡進行信息交換和通信,實現智能化識別、定位、跟蹤、監控和管理。物聯網的…

光伏電站鳥害解決方案,列式沖擊波聲壓光伏驅鳥器

光伏電站的運營過程中,最怕遇上鳥糞污染。鳥糞不僅難以清洗,還可能導致光伏組件損壞、降低發電效率。因此,制定并實施有效的驅鳥策略對于光伏電站的穩定運營至關重要。 針對光伏電站的鳥害問題,我們可以從以下幾個方面來解決&…

知名優秀定制線纜生產源頭工廠推薦-精工電聯:全程跟蹤監制,打造水下機器人線纜定制新標桿

在科技飛速發展的今天,精工電聯作為高科技智能化產品及自動化設備專用連接線束和連接器配套服務商,始終站在行業前沿。我們專注于為高科技行業提供高品質、優匹配的集成線纜和連接器定制服務,特別是在水下機器人線纜定制領域,通過…

CAN的TP模式和COM模式的區別

CAN的TP(傳輸協議)模式和COM(通信)模式主要涉及汽車網絡中的數據傳輸機制,兩者在功能、尋址方式和幀類型等方面有所不同。具體分析如下: 功能 TP模式:TP模式,即傳輸協議模式&#…

sql死鎖分析

一、重要參數 獲取事務信息:SELECT * FROM information_schema.INNODB_TRX; 獲取鎖等待:SELECT * FROM information_schema.INNODB_LOCK_WAITS; 查看鎖信息:SELECT * FROM information_schema.INNODB_LOCKS WHERE lock_trx_id IN () 二、case1:間隙鎖和x鎖互斥導致死鎖 1、背景…

安全高效海外倉系統:中小海外倉標準化管理的第一步

在當今全球化的商業背景中,可以說海外倉已經成為跨境電商供應鏈中不可或缺的一環。 尤其是對于那些處于成長階段的中小型海外倉來說,選擇一款安全高效并且符合其海外倉規模特點的wms管理系統尤其重要。 今天我們就來系統的了解一下,安全高效…

大廠AI團戰高考作文,華師一附中特級教師這樣打分

在人工智能的浪潮中, 人們不禁疑問: AI真的能超越人類嗎? 這究竟是現實還是幻想? 我們將目睹一場前所未有的較量: 百度文心一言、阿里通義千問、 騰訊混元、字節豆包 四家國內頂尖互聯網企業 精心打造的AI大模…

HBM簡介

1、什么是HBM HBMHigh Bandwidth Memory 是一種用于某些 GPU的 3D 堆疊 DRAM存儲器 (動態隨機存取存儲器)以及服務器、高性能計算 (HPC) 、網絡連接的內存接口。其實就是將很多個DDR芯片堆疊在一起后和GPU封裝在一起,實…

ROS socketcan_bridge使用說明

ROS socketcan_bridge使用說明(以ubuntu20.04為例) socketcan_bridge是什么 ROS針對socketcan提供了三個層次的驅動庫,分別是ros_canopen,socketcan_bridge和socketcan_interface。 socketcan_interface: 功能&#x…