中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Java設計模式中的原型模式詳解

發布時間:2021-09-15 20:01:29 來源:億速云 閱讀:162 作者:chen 欄目:開發技術

這篇文章主要介紹“Java設計模式中的原型模式詳解”,在日常操作中,相信很多人在Java設計模式中的原型模式詳解問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”Java設計模式中的原型模式詳解”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!

目錄
  • 介紹

  • 角色

  • Java語言提供的clone()方法

  • 代碼演示—克隆羊

    • 結論

  • 深淺拷貝

    • 深淺拷貝探討

    • 實現深克隆的方式一 : 手動對引用對象進行克隆

    • 實現深克隆的方式一 :序列化

  • 原型模式對單例模式的破壞

    • 優缺點

      • 適用場景

        • 原型模式在Spring中的應用場景

          介紹

          原型模式(Prototype Pattern):使用原型實例指定創建對象的種類,并且通過拷貝這些原型創建新的對象。原型模式是一種對象創建型模式。

          原型模式的工作原理很簡單:將一個原型對象傳給那個要發動創建的對象,這個要發動創建的對象通過請求原型對象拷貝自己來實現創建過程。

          原型模式是一種“另類”的創建型模式,創建克隆對象的工廠就是原型類自身,工廠方法由克隆方法來實現。

          需要注意的是通過克隆方法所創建的對象是全新的對象,它們在內存中擁有新的地址,通常對克隆所產生的對象進行修改對原型對象不會造成任何影響,每一個克隆對象都是相互獨立的。通過不同的方式修改可以得到一系列相似但不完全相同的對象。

          角色

          • Prototype(抽象原型類):它是聲明克隆方法的接口,是所有具體原型類的公共父類,可以是抽象類也可以是接口,甚至還可以是具體實現類。

          • ConcretePrototype(具體原型類):它實現在抽象原型類中聲明的克隆方法,在克隆方法中返回自己的一個克隆對象。

          • Client(客戶類):讓一個原型對象克隆自身從而創建一個新的對象,在客戶類中只需要直接實例化或通過工廠方法等方式創建一個原型對象,再通過調用該對象的克隆方法即可得到多個相同的對象。由于客戶類針對抽象原型類Prototype編程,因此用戶可以根據需要選擇具體原型類,系統具有較好的可擴展性,增加或更換具體原型類都很方便。

          原型模式的核心在于如何實現克隆方法。

          Java語言提供的clone()方法

          學過Java語言的人都知道,所有的Java類都繼承自 java.lang.Object。事實上,Object 類提供一個 clone() 方法,可以將一個Java對象復制一份。因此在Java中可以直接使用 Object 提供的 clone() 方法來實現對象的克隆,Java語言中的原型模式實現很簡單。

          需要注意的是能夠實現克隆的Java類必須實現一個 標識接口 Cloneable,表示這個Java類支持被復制。如果一個類沒有實現這個接口但是調用了clone()方法,Java編譯器將拋出一個 CloneNotSupportedException 異常。

          代碼演示—克隆羊

          具體原型類:

          //實現Cloneable接口
          @Data
          public class Sheep implements Cloneable
          {
              private String name;
              private Integer age;
              //重寫Object的clone方法
              @Override
              protected Object clone() throws CloneNotSupportedException 
              {
                  Sheep sheep=null;
                  sheep=(Sheep)super.clone();
                  return sheep;
              }
          }

          客戶端創建并克隆原型對象:

          //創建原型對象
                  Sheep sheep=new Sheep();
                  sheep.setAge(3);
                  sheep.setName("肖恩");
                  //克隆
                  Sheep sheep1 = sheep.clone();
                  Sheep sheep2=sheep.clone();
                  System.out.println(sheep1);
                  System.out.println(sheep2);
                  System.out.println(sheep1==sheep2);

          Java設計模式中的原型模式詳解

          結論

          • 克隆出來的對象,它們的內存地址均不同,說明不是同一個對象,克隆成功,克隆僅僅通過調用 super.clone() 即可。

          看一眼 Object#clone 方法

          protected native Object clone() throws CloneNotSupportedException;

          這是一個 native 關鍵字修飾的方法

          一般而言,Java語言中的clone()方法滿足:

          • 對任何對象x,都有 x.clone() != x,即克隆對象與原型對象不是同一個對象;

          • 對任何對象x,都有 x.clone().getClass() == x.getClass(),即克隆對象與原型對象的類型一樣;

          • 如果對象x的 equals() 方法定義恰當,那么 x.clone().equals(x) 應該成立。

          • 為了獲取對象的一份拷貝,我們可以直接利用Object類的clone()方法,具體步驟如下:

          在派生類中覆蓋基類的 clone() 方法,并聲明為public;

          在派生類的 clone() 方法中,調用 super.clone();

          派生類需實現Cloneable接口。

          此時,Object類相當于抽象原型類,所有實現了Cloneable接口的類相當于具體原型類。

          深淺拷貝

          pig類:

          @Data
          @AllArgsConstructor
          @NoArgsConstructor
          public class Pig 
          {
              String name;
              Integer age;
          }

          sheep類:

          //實現Cloneable接口
          @Data
          public class Sheep implements Cloneable
          {
              private String name;
              private Integer age;
              private  Pig pig;
              //重寫Object的clone方法
              @Override
              protected Sheep clone() throws CloneNotSupportedException
              {
                  Sheep sheep=null;
                  sheep=(Sheep)super.clone();
                  return sheep;
              }
          }

          客戶端進行克隆:

          public class test
          {
              @Test
              public void test() throws CloneNotSupportedException {
                  //創建原型對象
                  Sheep sheep=new Sheep();
                  sheep.setAge(3);
                  sheep.setName("肖恩");
                  sheep.setPig(new Pig("大忽悠",3));
                  //克隆
                  Sheep sheep1 = sheep.clone();
                  Sheep sheep2=sheep.clone();
                  System.out.println(sheep1);
                  System.out.println(sheep2);
                  System.out.println(sheep1==sheep2);
                  System.out.println("==============================");
                  System.out.println(sheep1.getPig()==sheep2.getPig());
              }
          }

          Java設計模式中的原型模式詳解

          這里對Sheep類里面的引用類型Pig的克隆方式只是簡單的地址拷貝,即淺拷貝操作

          深淺拷貝探討

          淺克隆:

          • 在淺克隆中,如果原型對象的成員變量是值類型,將復制一份給克隆對象;如果原型對象的成員變量是引用類型,則將引用對象的地址復制一份給克隆對象,也就是說原型對象和克隆對象的成員變量指向相同的內存地址。

          • 簡單來說,在淺克隆中,當對象被復制時只復制它本身和其中包含的值類型的成員變量,而引用類型的成員對象并沒有復制。

          • 在Java語言中,通過覆蓋Object類的clone()方法可以實現淺克隆

          深克隆:

          • 在深克隆中,無論原型對象的成員變量是值類型還是引用類型,都將復制一份給克隆對象,深克隆將原型對象的所有引用對象也復制一份給克隆對象。

          • 簡單來說,在深克隆中,除了對象本身被復制外,對象所包含的所有成員變量也將復制。

          • 在Java語言中,如果需要實現深克隆,可以通過序列化(Serialization)等方式來實現。需要注意的是能夠實現序列化的對象其類必須實現Serializable接口,否則無法實現序列化操作。

          實現深克隆的方式一 : 手動對引用對象進行克隆

          Pig類首先需要實現克隆即可,并重寫clone方法:

          @Data
          @AllArgsConstructor
          @NoArgsConstructor
          public class Pig implements Cloneable
          {
              String name;
              Integer age;
              @Override
              protected Object clone() throws CloneNotSupportedException {
                  return super.clone();
              }
          }

          sheep類:

          //實現Cloneable接口
          @Data
          public class Sheep implements Cloneable
          {
              private String name;
              private Integer age;
              private  Pig pig;
              //重寫Object的clone方法
              @Override
              protected Sheep clone() throws CloneNotSupportedException
              {
                  Sheep sheep=null;
                  sheep=(Sheep)super.clone();
                  sheep.pig=(Pig)sheep.pig.clone();
                  return sheep;
              }
          }

          Java設計模式中的原型模式詳解

          實現深克隆的方式一 :序列化

          對象可以序列化的前提是實現了Serializable接口,這里Sheep和Pig都需要實現該接口

          pig類:

          @Data
          @AllArgsConstructor
          @NoArgsConstructor
          public class Pig implements Serializable
          {
              String name;
              Integer age;
          }

          sheep類:

          //實現Cloneable接口
          @Data
          public class Sheep implements Serializable
          {
              private String name;
              private Integer age;
              private  Pig pig;
           //序列化方式完成深拷貝
              public Sheep deepClone() throws IOException, ClassNotFoundException {
                  //先將要序列化的對象寫入流中
                  ByteArrayOutputStream baot=new ByteArrayOutputStream();
                  //ObjectOutputStream構造函數的參數是,將對象流寫入到哪里
                  ObjectOutputStream oot=new ObjectOutputStream(baot);
                    oot.writeObject(this);
                    //將序列化的對象從流中讀取出來
                  ByteArrayInputStream bait=new ByteArrayInputStream(baot.toByteArray());
                  ObjectInputStream oit=new ObjectInputStream(bait);
                  return (Sheep) oit.readObject();
              }
          }

          Java設計模式中的原型模式詳解

          原型模式對單例模式的破壞

          餓漢式單例模式如下:

          public class HungrySingleton implements Serializable, Cloneable {
              private final static HungrySingleton hungrySingleton;
              static {
                  hungrySingleton = new HungrySingleton();
              }
              private HungrySingleton() 
              {}
              public static HungrySingleton getInstance() {
                  return hungrySingleton;
              }
              private Object readResolve() {
                  return hungrySingleton;
              }
              @Override
              protected Object clone() throws CloneNotSupportedException {
                  return super.clone();
              }
          }

          使用反射獲取對象,測試如下

          public class Test {
              public static void main(String[] args) throws CloneNotSupportedException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
                  HungrySingleton hungrySingleton = HungrySingleton.getInstance();
                  Method method = hungrySingleton.getClass().getDeclaredMethod("clone");
                  method.setAccessible(true);
                  HungrySingleton cloneHungrySingleton = (HungrySingleton) method.invoke(hungrySingleton);
                  System.out.println(hungrySingleton);
                  System.out.println(cloneHungrySingleton);
              }
          }

          輸出

          com.designpattern.HungrySingleton@34c45dca
          com.designpattern.HungrySingleton@52cc8049

          可以看到,通過原型模式,我們把單例模式給破壞了,現在有兩個對象了

          為了防止單例模式被破壞,我們可以:不實現 Cloneable 接口;或者把 clone 方法改為如下

          @Override
              protected Object clone() throws CloneNotSupportedException {
                  return getInstance();
              }

          優缺點

          原型模式的主要優點如下:

          • 當創建新的對象實例較為復雜時,使用原型模式可以簡化對象的創建過程,通過復制一個已有實例可以提高新實例的創建效率。

          • 擴展性較好,由于在原型模式中提供了抽象原型類,在客戶端可以針對抽象原型類進行編程,而將具體原型類寫在配置文件中,增加或減少產品類對原有系統都沒有任何影響。

          • 原型模式提供了簡化的創建結構,工廠方法模式常常需要有一個與產品類等級結構相同的工廠等級結構,而原型模式就不需要這樣,原型模式中產品的復制是通過封裝在原型類中的克隆方法實現的,無須專門的工廠類來創建產品。

          • 可以使用深克隆的方式保存對象的狀態,使用原型模式將對象復制一份并將其狀態保存起來,以便在需要的時候使用(如恢復到某一歷史狀態),可輔助實現撤銷操作。

          原型模式的主要缺點如下:

          • 需要為每一個類配備一個克隆方法,而且該克隆方法位于一個類的內部,當對已有的類進行改造時,需要修改源代碼,違背了“開閉原則”。

          • 在實現深克隆時需要編寫較為復雜的代碼,而且當對象之間存在多重的嵌套引用時,為了實現深克隆,每一層對象對應的類都必須支持深克隆,實現起來可能會比較麻煩。

          適用場景

          • 創建新對象成本較大(如初始化需要占用較長的時間,占用太多的CPU資源或網絡資源),新的對象可以通過原型模式對已有對象進行復制來獲得,如果是相似對象,則可以對其成員變量稍作修改。

          • 如果系統要保存對象的狀態,而對象的狀態變化很小,或者對象本身占用內存較少時,可以使用原型模式配合備忘錄模式來實現。

          • 需要避免使用分層次的工廠類來創建分層次的對象,并且類的實例對象只有一個或很少的幾個組合狀態,通過復制原型對象得到新實例可能比使用構造函數創建一個新實例更加方便。

          原型模式在Spring中的應用場景

          在Spring中,用戶也可以采用原型模式來創建新的Bean實例,從而實現每次獲取的是通過克隆生成的新實例,對其進行修改時對原有實例對象不造成任何影響。

          這里的原型模式,也就是常說的Spring中的多實例模式,Spring中還有大家熟知的單實例模式,即Sigleton

          到此,關于“Java設計模式中的原型模式詳解”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!

          向AI問一下細節

          免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

          AI

          库尔勒市| 忻城县| 谢通门县| 丘北县| 西充县| 南陵县| 怀宁县| 濮阳县| 广饶县| 盐山县| 万源市| 汕尾市| 鄂托克旗| 宿州市| 吕梁市| 平谷区| 四会市| 汾西县| 泰安市| 察哈| 文水县| 临江市| 汉寿县| 揭阳市| 沁水县| 河西区| 嘉义县| 桐庐县| 无锡市| 鄂托克前旗| 富顺县| 南澳县| 枣阳市| 常山县| 尚义县| 洛川县| 延津县| 瓦房店市| 休宁县| 沐川县| 镇江市|