(四)趣學設計模式 之 原型模式!

在這里插入圖片描述

目錄

    • 一、 啥是原型模式?
    • 二、 為什么要用原型模式?
    • 三、 原型模式怎么實現?
    • 四、 原型模式的應用場景
    • 五、 原型模式的優點和缺點
    • 六、 總結

🌟我的其他文章也講解的比較有趣😁,如果喜歡博主的講解方式,可以多多支持一下,感謝🤗!
🌟了解抽象工廠模式請看: (三)趣學設計模式 之 抽象工廠模式!

這篇文章帶你詳細認識一下設計模式中的原型模式

一、 啥是原型模式?

原型模式,說白了,就是“山寨”! 🤣 你有一個寶貝,不想自己辛辛苦苦再做一個,就找個復印機(克隆方法),咔嚓一下,復制一個一模一樣的出來!

  • 對象的創建成本很高: 就像造火箭 🚀,太費勁了,不如復制一個!
  • 需要創建大量相似對象: 就像克隆羊 🐑,要一大堆一樣的羊,一個個生太慢了!
  • 希望隱藏對象的創建細節: 就像做菜 🍳,你只想吃,不想知道怎么做的!

二、 為什么要用原型模式?

用原型模式,好處多多:

  • 省錢省力: 不用重復造輪子 🚗,直接復制,省時省力!
  • 靈活多變: 想復制啥就復制啥,不用提前定好,很靈活!
  • 簡單易懂: 不用管對象怎么創建的,直接復制就行,代碼更簡單!
  • 避免麻煩: 不用創建一堆亂七八糟的子類,省心!

三、 原型模式怎么實現?

原型模式主要有兩種“山寨”方法:

  • 淺拷貝(Shallow Copy)
  • 深拷貝(Deep Copy)

實現原型模式的關鍵點

  • Cloneable 接口: 就像一個“允許復制”的標簽 🏷?,貼上這個標簽,才能被復印!
  • Object 類的 clone() 方法: 就像復印機的基本功能,只能復印表面信息(淺拷貝)!
  • 重寫 clone() 方法: 就像升級復印機,讓它可以復印所有信息(深拷貝)!

1.淺拷貝(Shallow Copy):只復制表面! 🤏

淺拷貝就像復印身份證 🪪,你復印了一張身份證,上面的名字、地址都一樣,但是里面的芯片還是原來的那個。如果原來的身份證信息變了,復印件也會跟著變!

// 1. 定義原型接口 (Cloneable 是 Java 內置的接口)
interface Prototype extends Cloneable {Prototype clone(); // 克隆方法
}// 2. 定義具體原型類
class Sheep implements Prototype {private String name;private int age;private Address address; // 引用類型屬性public Sheep(String name, int age, Address address) {this.name = name;this.age = age;this.address = address;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public Address getAddress() {return address;}public void setAddress(String city) {this.address.setCity(city);}@Overridepublic Sheep clone() {try {// 淺拷貝:直接調用 Object 類的 clone() 方法return (Sheep) super.clone();} catch (CloneNotSupportedException e) {System.out.println("克隆失敗! 😭");return null;}}@Overridepublic String toString() {return "Sheep{" +"name='" + name + '\'' +", age=" + age +", address=" + address +'}';}
}// 地址類 (引用類型)
class Address {private String city;public Address(String city) {this.city = city;}public String getCity() {return city;}public void setCity(String city) {this.city = city;}@Overridepublic String toString() {return "Address{" +"city='" + city + '\'' +'}';}
}// 3. 客戶端使用
public class Client {public static void main(String[] args) {// 創建原型對象Address address = new Address("北京");Sheep originalSheep = new Sheep("多莉", 3, address);// 克隆原型對象Sheep clonedSheep = originalSheep.clone();// 打印原始對象和克隆對象System.out.println("原始羊: " + originalSheep);System.out.println("克隆羊: " + clonedSheep);// 修改原始對象的引用類型屬性originalSheep.setAddress("上海");// 再次打印原始對象和克隆對象System.out.println("修改后的原始羊: " + originalSheep);System.out.println("修改后的克隆羊: " + clonedSheep);}
}

代碼解釋:

  • Prototype:原型接口,定義了克隆方法。
  • Sheep:具體原型類,實現了 Prototype 接口,表示羊。
  • clone():克隆方法,用于創建對象的副本。
  • Address:地址類,作為 Sheep 類的引用類型屬性。

輸出結果:

原始羊: Sheep{name='多莉', age=3, address=Address{city='北京'}}
克隆羊: Sheep{name='多莉', age=3, address=Address{city='北京'}}
修改后的原始羊: Sheep{name='多莉', age=3, address=Address{city='上海'}}
修改后的克隆羊: Sheep{name='多莉', age=3, address=Address{city='上海'}}

分析:

可以看到,修改原始羊的地址后,克隆羊的地址也跟著改變了!這是因為淺拷貝只復制了地址的“指針”,原始羊和克隆羊指向的是同一個地址,所以一個變了,另一個也跟著變!

2. 深拷貝(Deep Copy):徹底復制! 💯

深拷貝就像克隆一只完整的羊 🐑,你克隆了一只羊,它有自己的名字、年齡和地址,和原來的羊完全沒有關系。即使原來的羊死了,克隆羊還是活蹦亂跳的!

import java.io.*;class Sheep implements Prototype, Serializable { // 注意實現 Serializable 接口private String name;private int age;private Address address;public Sheep(String name, int age, Address address) {this.name = name;this.age = age;this.address = address;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public Address getAddress() {return address;}public void setAddress(Address address) {this.address = address;}@Overridepublic Sheep 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 (Sheep) ois.readObject();} catch (Exception e) {System.out.println("克隆失敗! 😭");return null;}}@Overridepublic String toString() {return "Sheep{" +"name='" + name + '\'' +", age=" + age +", address=" + address +'}';}
}class Address implements Serializable { // 注意實現 Serializable 接口private String city;public Address(String city) {this.city = city;}public String getCity() {return city;}public void setCity(String city) {this.city = city;}@Overridepublic String toString() {return "Address{" +"city='" + city + '\'' +'}';}
}public class Client {public static void main(String[] args) {// 創建原型對象Address address = new Address("北京");Sheep originalSheep = new Sheep("多莉", 3, address);// 克隆原型對象Sheep clonedSheep = originalSheep.clone();// 打印原始對象和克隆對象System.out.println("原始羊: " + originalSheep);System.out.println("克隆羊: " + clonedSheep);// 修改原始對象的引用類型屬性address.setCity("上海");// 再次打印原始對象和克隆對象System.out.println("修改后的原始羊: " + originalSheep);System.out.println("修改后的克隆羊: " + clonedSheep);}
}

注意: 使用序列化和反序列化實現深拷貝,需要確保對象及其所有屬性都實現了 Serializable 接口。

輸出結果:

原始羊: Sheep{name='多莉', age=3, address=Address{city='北京'}}
克隆羊: Sheep{name='多莉', age=3, address=Address{city='北京'}}
修改后的原始羊: Sheep{name='多莉', age=3, address=Address{city='上海'}}
修改后的克隆羊: Sheep{name='多莉', age=3, address=Address{city='北京'}}

分析:

可以看到,修改原始羊的地址后,克隆羊的地址沒有改變!這是因為深拷貝復制了地址的所有信息,原始羊和克隆羊擁有不同的地址,所以一個變了,另一個不會受到影響!

四、 原型模式的應用場景

  • 游戲開發: 游戲里的怪物 👾,不用一個個設計,復制幾個改改屬性就行!
  • 文檔編輯器: 文檔的模板 📄,復制一份改改,就能生成新的文檔!
  • 圖形編輯器: 圖形對象 🖼?,復制一份改改顏色、大小,就能得到新的圖形!
  • 配置管理: 軟件的配置 ??,復制一份改改,就能適應不同的環境!
  • 報表生成: 報表的模板 📊,復制一份改改數據,就能生成不同的報表!

五、 原型模式的優點和缺點

優點:

  • 省錢省力: 不用重新創建對象,直接復制,就像復制粘貼一樣簡單,大大提高了效率!
  • 隱藏秘密: 客戶端不用知道對象是怎么創建的,只需要知道怎么復制就行,保護了對象的內部結構!
  • 靈活應變: 可以在運行時動態地復制對象,想復制啥就復制啥,非常靈活!
  • 減少麻煩: 不用創建一堆子類,避免了代碼的膨脹,讓代碼更簡潔!

缺點:

  • 復制很麻煩: 特別是深拷貝,要復制對象的所有信息,就像搬家一樣,很麻煩!
  • 破壞隱私: 為了復制對象,可能需要訪問對象的私有屬性,就像偷看別人的日記一樣,破壞了對象的封裝性!
  • 需要貼標簽: 在 Java 中,需要實現 Cloneable 接口才能被復制,就像需要貼上“允許復制”的標簽,有點麻煩!
  • 可能出錯: 有時候復制操作可能不會執行構造函數,就像克隆羊沒有靈魂一樣,可能會導致對象的狀態不正確!

六、 總結

  • 原型模式就是“山寨”大法,通過復制現有對象來創建新對象!
  • 適用于需要大量相似對象、對象創建成本高、需要隱藏對象創建細節的場景!
  • 有兩種“山寨”方法:淺拷貝和深拷貝!
  • 淺拷貝只復制表面信息,深拷貝復制所有信息!
  • 要根據實際情況選擇合適的“山寨”方法!
  • 使用原型模式需要注意一些問題,比如破壞封裝性、可能出錯等等!

希望這篇文章能讓你徹底理解原型模式! 👍
看完請看:(五)趣學設計模式 之 建造者模式!

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

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

相關文章

完美解決:.vmx 配置文件是由 VMware 產品創建,但該產品與此版 VMware Workstation 不兼容

參考文章:該產品與此版 VMware Workstation 不兼容,因此無法使用 問題描述 當嘗試使用 VMware Workstation 打開別人的虛擬機時,可能會遇到以下報錯: 此問題常見于以下場景: 從其他 VMware 版本(如 ESX…

Linux——安裝Git的方法

安裝Git的命令: yum -y install git查看Git的版本: git --version

編程小白沖Kaggle每日打卡(13)--kaggle學堂:<機器學習簡介>基礎數據探索

Kaggle官方課程鏈接:Basic Data Exploration 本專欄旨在Kaggle官方課程的漢化,讓大家更方便地看懂。 Basic Data Exploration 加載并理解您的數據。 使用Pandas熟悉您的數據 任何機器學習項目的第一步都是熟悉數據。您將使用Pandas庫進行此操作。Pand…

從零開始的網站搭建(以照片/文本/視頻信息通信網站為例)

本文面向已經有一些編程基礎(會至少一門編程語言,比如python),但是沒有搭建過web應用的人群,會寫得盡量細致。重點介紹流程和部署云端的步驟,具體javascript代碼怎么寫之類的,這里不會涉及。 搭…

【Java項目】基于SpringBoot的【高校校園點餐系統】

【Java項目】基于SpringBoot的【高校校園點餐系統】 技術簡介:采用Java技術、MySQL數據庫、B/S結構實現。 系統簡介:高校校園點餐系統是一個面向高校師生的在線點餐平臺,主要分為前臺和后臺兩大模塊。前臺功能模塊包括(1&#xff…

Django check_password原理

check_password 是 Django 提供的一個用于密碼校驗的函數,它的工作原理是基于密碼哈希算法的特性。 Django 的 make_password 函數在生成密碼哈希時,會使用一個隨機的 salt(鹽值)。這個 salt 會與密碼一起進行哈希運算&#xff0…

Vulnhun靶機-kioptix level 4-sql注入萬能密碼拿到權限ssh連接利用mysql-udf漏洞提權

目錄 一、環境搭建信息收集掃描ip掃描開放端口掃描版本服務信息指紋探測目錄掃描 二、Web滲透sql注入 三、提權UDF提權修改權限 一、環境搭建 然后選擇靶機所在文件夾 信息收集 本靶機ip和攻擊機ip 攻擊機:192.168.108.130 靶機:192.168.108.141 掃描…

PHP 會話(Session)實現用戶登陸功能

Cookie是一種在客戶端和服務器之間傳遞數據的機制。它是由服務器發送給客戶端的小型文本文件,保存在客戶端的瀏覽器中。每當瀏覽器向同一服務器發送請求時,它會自動將相關的Cookie信息包含在請求中,以便服務器可以使用這些信息來提供個性化的…

PAT 甲級 1090 Highest Price in Supply Chain

構造一個二維數組 v &#xff0c;v[i] 存放指向 i 的所有元素。 構造隊列 q 存放每個待讀取的節點。 構造數組 high 存放每個節點的高度&#xff08;第幾級經銷商&#xff09; #include<iostream> #include<queue> #include<cmath> using namespace std; …

DeepSeek掘金——SpringBoot 調用 DeepSeek API 快速實現應用開發

Spring Boot 實現 DeepSeek API 調用 1. 項目依賴 在 pom.xml 中添加以下依賴: <dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-webflux</artifactId></dependency>&l…

算法——數學建模的十大常用算法

數學建模的十大常用算法在數學建模競賽和實際問題解決中起著至關重要的作用。以下是這些算法的具體信息、應用場景以及部分算法的C語言代碼示例&#xff08;由于篇幅限制&#xff0c;這里只給出部分算法的簡要代碼或思路&#xff0c;實際應用中可能需要根據具體問題進行調整和擴…

推薦幾款SpringBoot項目手腳架

作為程序員、一般需要搭建項目手腳架時、都會去Gitee或Github上去找、但是由于Github在國內并不穩定、所以就只能去Gitee去上查找。 不同語言檢索方式不一樣、但是也類似。 Gitee WEB應用開發 / 后臺管理框架 芋道源碼 ELADMIN 后臺管理系統 一個基于 Spring Boot 2.7.1…

智能自動化新紀元:AI與UiPath RPA的協同應用場景與技術實踐

智能自動化新紀元&#xff1a;AI與UiPath RPA的協同應用場景與技術實踐 引言 在數字化轉型的浪潮中&#xff0c;企業對于自動化技術的需求已從簡單的任務執行轉向更復雜的智能決策。傳統RPA&#xff08;Robotic Process Automation&#xff09;通過模擬人類操作處理重復性任務…

數據結構:動態數組vector

vector 是 C 標準庫的動態數組。 在C語言中一般初學者會使用malloc&#xff0c;int[n]等方式來創建靜態數組&#xff0c;但是這種方式繁瑣且容易出錯。我們做算法題一般使用動態數組vector&#xff0c; 并且在刷題網站的題目給的輸入一般也是vector類型。 示例&#xff1a;vect…

基于深度學習的信號濾波:創新技術與應用挑戰

一、引言 1.1 研究背景 隨著科技的不斷發展&#xff0c;信號處理領域面臨著越來越復雜的挑戰。在眾多信號處理技術中&#xff0c;基于深度學習的信號濾波技術逐漸嶄露頭角&#xff0c;成為研究的熱點。 基于深度學習的信號濾波在信號處理領域具有至關重要的地位。如今&#…

前端八股——JS+ES6

前端八股&#xff1a;JSES6 說明&#xff1a;個人總結&#xff0c;用于個人復習回顧&#xff0c;將持續改正創作&#xff0c;已在語雀公開&#xff0c;歡迎評論改正。

醫院安全(不良)事件上報系統源碼,基于Laravel8開發,依托其優雅的語法與強大的擴展能力

醫院安全&#xff08;不良&#xff09;事件上報系統源碼 系統定義&#xff1a; 規范醫院安全&#xff08;不良&#xff09;事件的主動報告&#xff0c;增強風險防范意識&#xff0c;及時發現醫院不良事件和安全隱患&#xff0c;將獲取的醫院安全信息進行分析反饋&#xff0c;…

H3C交換機路由器防火墻FTP/TFTP服務器搭建。

軟件介紹。 3CDaemon 2.0 - Download 3CDaemon 是一款集成了多種網絡服務功能的工具軟件&#xff0c;主要用于網絡管理和文件傳輸&#xff0c;支持TFTP、FTP、Syslog等多種協議&#xff0c;廣泛應用于網絡設備的配置和管理。 1. 主要功能 TFTP服務器&#xff1a;支持TFTP協議…

數據庫連接管理--Java連接數據庫的幾種方式

1.數據庫連接管理 1.1 使用JDBC獲取連接 JDBC是Java標準庫提供的API&#xff0c;用于連接和操作關系型數據庫。它是最基礎、最常用的數據庫連接方式。 步驟&#xff1a; 加載數據庫驅動。建立連接。創建Statement或PreparedStatement對象。執行SQL查詢或更新。處理結果集。關…

如何使用Spring boot框架實現圖書管理系統

使用 Spring Boot 框架實現圖書管理系統可以按照以下步驟進行&#xff0c;涵蓋了從項目搭建、數據庫設計、后端接口開發到前端頁面展示的整個流程。 1. 項目搭建 可以使用 Spring Initializr&#xff08;https://start.spring.io/ &#xff09;來快速創建一個 Spring Boot 項目…