原型模式和深拷貝,淺拷貝

来源:https://www.cnblogs.com/changming06/archive/2023/09/08/17688657.html
-Advertisement-
Play Games

### 原型模式 #### 案例引入 ##### 克隆羊問題 有一隻羊,姓名為tom,年齡為1,顏色為白色,編寫程式創建和tom羊屬性完全相同的羊。 ##### 傳統方式解決 代碼實現 ```java public class Sheep { private String name; private ...


原型模式

案例引入

克隆羊問題

有一隻羊,姓名為tom,年齡為1,顏色為白色,編寫程式創建和tom羊屬性完全相同的羊。

傳統方式解決

代碼實現

public class Sheep {
    private String name;
    private int age;
    private String color;

    public Sheep() {
    }

    public Sheep(String name, int age, String color) {
        this.name = name;
        this.age = age;
        this.color = color;
    }

    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 String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }
}
//測試
public class Client {
    public static void main(String[] args) {
        Sheep sheep = new Sheep("tom", 1, "白色");
        Sheep sheep1 = new Sheep(sheep.getName(), sheep.getAge(), sheep.getColor());
        Sheep sheep2 = new Sheep(sheep.getName(), sheep.getAge(), sheep.getColor());
        Sheep sheep3 = new Sheep(sheep.getName(), sheep.getAge(), sheep.getColor());
        /**
        *  public String toString() {//Object類的toString()方法
        *      return getClass().getName() + "@" + Integer.toHexString(hashCode());//會輸出全類名@符還有16進位的hashCode值
        *  }
        */
        System.out.println(sheep);//輸出的對象的hashcode的值不相同,輸出對象時,會預設的調用對象的toString()方法
        System.out.println(sheep1);
        System.out.println(sheep2);
        System.out.println(sheep3);
    }
}
傳統實現方式分析
  • 1.優點是好理解,簡單易操作。
  • 2.缺點進行新對象創建時,總是需要重新獲取原始對象的屬性,如果創建的對象複雜時,效率很低。
  • 3.缺點,總是需要重新初始化對象(new操作),而不是動態的根據已有對象去創建,不靈活。
  • 4.改進思路,Java中Object類是所有類的基類,Object類提供了一個clone()方法,該方法可以將一個Java對象賦值一份,但是需要想使用這個方法的類必須要實現一個Cloneable介面,
    該介面才能複製,且具有複製的能力。

原型模式

基本介紹
  • 1.原型模式(Prototype Pattern)是指,用原型實例創建對象的種類,並且通過拷貝這些原型,創建新的對象。
  • 2.原型模式是一種設計型模式,允許一個對象再創建另一個可對象,無需知道創建的細節。
  • 3.工作原理是,通過將一個原型對象通過clone或者其他自己寫的克隆方法,拷貝自身。
用原型模式實現案例
public class Sheep implements Cloneable{
    private String name;
    private int age;
    private String color;
    private String address = "蒙古羊";
    private Sheep friend;

    public Sheep() {
    }

    public Sheep(String name, int age, String color) {
        this.name = name;
        this.age = age;
        this.color = color;
    }

    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 String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public Sheep getFriend() {
        return friend;
    }

    public void setFriend(Sheep friend) {
        this.friend = friend;
    }

    @Override
    public String toString() {
        return "Sheep{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", color='" + color + '\'' +
                ", address='" + address + '\'' +
                ", friend=" + friend +
                '}';
    }

    @Override
    protected Object clone() {
        Sheep sheep = null;
        try{
            sheep = (Sheep)super.clone();
        }catch (Exception e){
            System.out.println(e.getMessage());
        }
        return sheep;
    }
}

public class Client {
    public static void main(String[] args) {
        Sheep sheep = new Sheep("tom", 1, "白色");
        sheep.setFriend(new Sheep("jack",1,"黑色"));

        Sheep sheep1 = (Sheep)sheep.clone();
        Sheep sheep2 = (Sheep)sheep.clone();

        System.out.println("sheep1=" + sheep1 + "sheep1.friend\n" + sheep1.getFriend().hashCode());//輸出的hashCode值相同
        System.out.println("sheep2=" + sheep2 + "sheep2.friend\n" + sheep2.getFriend().hashCode());
    }
}

原型模式在Spring框架中的使用

//AbstractBeanFactory類doGetBean()的部分代碼
else if (mbd.isPrototype()) {//判斷當前bean是否是原型類型
   // It's a prototype -> create a new instance.
   Object prototypeInstance = null;
   try {
      beforePrototypeCreation(beanName);
      prototypeInstance = createBean(beanName, mbd, args);
   }
   finally {
      afterPrototypeCreation(beanName);
   }
   bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}

深拷貝和淺拷貝

淺拷貝介紹
  • 1.淺拷貝,對於基本數據類型的屬性,淺拷貝會直接進行值傳遞,也就是將該屬性值複製一份給新的對象。
  • 2.對於數據類型是引用數據類型的成員變數,比如說成員變數是某個數組,某個類的對象等,淺拷貝會進行引用傳遞,也就是只是將該成員變數的引用值(記憶體地址)複製給新的對象。實際上兩個對象的該成員變數都指向一個實例。在這種情況下,一個對象對於引用類型的屬性的改變,就會影響到另一個對象的引用屬性。
  • 3.前面克隆羊就是淺拷貝。
  • 4.淺拷貝是使用預設的clone方法來實現 sheep = (sheep) super.clone();
深拷貝介紹
  • 1.複製對象的所有屬性,進行拷貝,就是說,基本數據類型拷貝成員變數值,引用數據類型的屬性都申請存儲空間,並複製每個引用類型屬性所引用的對象,進行拷貝。也就是說對象進行深拷貝要對整個對象(包括對象的引用屬性)進行拷貝。
  • 2.深拷貝實現方式,重寫clone()和通過對象序列化和反序列化實現深拷貝(推薦)
    序列化,簡單的說,就是將對象存儲到磁碟。反序列化,將磁碟存儲的對象讀取到記憶體。
    代碼演示
public class Money implements Serializable, Cloneable{
    private int account;

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
public class Person implements Serializable, Cloneable {
    private String name;
    private int age;
    private Money money;
    private static final long serialVersionID = 1L;

    public Person(String name, int age, Money money) {
        this.name = name;
        this.age = age;
        this.money = money;
    }

    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 Money getMoney() {
        return money;
    }

    public void setMoney(Money money) {
        this.money = money;
    }

    //1.重寫clone方法完成深拷貝
    //這種方式存在問題,如果一個類中存在引用屬性且沒有為該屬性複製
    //就會導致在進行克隆時會出現NullPointException,可以在clone前進行驗證解決
    @Override
    protected Object clone() throws CloneNotSupportedException {
        Person person = null;
        //1.完成基本數據類型的clone
        person = (Person) super.clone();
        //2.對引用類型的屬性,進行單獨處理
        person.money = (Money) money.clone();
        return person;
    }

    //方式2 通過對象的序列化和反序列化實現
    public Object deepClone() {
        ByteArrayOutputStream bos = null;
        ObjectOutputStream oos = null;
        ByteArrayInputStream bis = null;
        ObjectInputStream ois = null;
        Object object = null;
        try{
            bos = new ByteArrayOutputStream();
            oos = new ObjectOutputStream(bos);
            oos.writeObject(this);//當前對象序列化到對象輸出流中
            bis = new ByteArrayInputStream(bos.toByteArray());
            ois = new ObjectInputStream(bis);//從輸出流中反序列化到輸入流中
            object = ois.readObject();//讀取對象
        }catch (IOException | ClassNotFoundException e){
            e.printStackTrace();
        }finally {
            try {
                bos.close();
                oos.close();
                bis.close();
                ois.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return object;
    }
}
//測試
public class TestDeepClone {
    public static void main(String[] args) throws CloneNotSupportedException {
        Money money = new Money();
        Person person = new Person("wind", 27, null);

        Person clone = (Person) person.clone();
//        Person clone = (Person) person.deepClone();
        System.out.println(person.getMoney().hashCode() + "-" + clone.getMoney().hashCode());
    }
}

註意事項和細節

  • 1.創建新的對象比較複雜,可以利用原型模式簡化對象的創建過程,同時也能提高效率。
  • 2.不用再重新初始化對象,而是動態的根據對象的運行進行創建。
  • 3.如果原始對象發送變化(增加或減少屬性),克隆對象的也不要發送變化,無需修改克隆的代碼。
  • 4.實現深拷貝,需要比較複雜的代碼。
  • 5.缺點,要為需要克隆的類,配一個克隆方法,這對新創建的類不難,但是對已有的類,需要修改源代碼,違反了ocp。
    只是為了記錄自己的學習歷程,且本人水平有限,不對之處,請指正。

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 最近研發apk校驗服務,很多游戲安裝包兩三個G,如果整個拿去校驗,耗時基本二十多秒,這還僅僅是校驗的時間,如果加上下載的時間,等待時間太長了 網上很多方案嘗試了一下,不太行 1、fast md5 一個第三方庫,csdn有人用過說可以提升40%的速度,然後我去試了一下,本來9秒可以完成的校驗,變成了2 ...
  • 如果你會 Java, 那麼來看一看 Kotlin , 基礎入門。 如果你不理解 Kotlin 的lambda 表達式,那麼來看一看,幫助你真正理解函數類型,lambda 表達式。 ...
  • >我們是[袋鼠雲數棧 UED 團隊](http://ued.dtstack.cn/),致力於打造優秀的一站式數據中台產品。我們始終保持工匠精神,探索前端道路,為社區積累並傳播經驗價值。 >本文作者:琉易 [liuxianyu.cn](https://link.juejin.cn/?target=ht ...
  • 需求: 設計一個標題,讓中間部分隨著文字而撐大,同時文字漸變,兩邊自適應,這種情況就不能用傳統的背景圖片了,想到可以使用圖片邊框來做 解決思路: 1.需要一個大盒子和三個小盒子 2.大盒子設置display:flex; 左右兩個小盒子分別設置flex-grow; 並設置背景圖片 3.給中間盒子設置邊 ...
  • 此篇文章用於記錄柏成從零開發一個canvas九宮格手勢解鎖器的歷程。我們基於 canvas 實現了一款簡單的九宮格手勢解鎖器,用戶可以通過在九宮格中繪製特定的手勢來解鎖。 ...
  • ##一、定義 **使用原型實例指定待創建對象的類型,並且通過複製這個原型來創建新的對象。原型模式是一種創建型模式。** ##二、描述 **包含以下三個角色:** ![](https://img2023.cnblogs.com/blog/1780813/202305/1780813-202305271 ...
  • 本文給大家介紹了什麼是"編程範式",選擇合適的編程範式可以提高代碼的可讀性、可維護性和可擴展性。 一、 什麼是編程範式? "編程範式"是一種編程思想的總稱,它是指在編寫程式時所採用的基本方法和規範。常見的編程範式有面向對象、函數式、邏輯式等。 選擇合適的編程範式可以提高代碼的可讀性、可維護性和可擴展 ...
  • 淺聊一下SpringMVC的核心組件以及通過源碼瞭解其執行流程 MVC作為WEB項目開發的核心環節,正如三個單詞的分解那樣,Controller(控制器)將View(視圖、用戶客戶端)與Model(javaBean:封裝數據)分開構成了MVC,今天我們淺聊一下SpringMVC的相關組件以及通過源碼... ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...