激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術(shù)|正則表達(dá)式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務(wù)器之家 - 編程語言 - Java教程 - JAVA設(shè)計(jì)模式---原型模式你了解嗎

JAVA設(shè)計(jì)模式---原型模式你了解嗎

2021-12-16 13:01大忽悠愛忽悠 Java教程

這篇文章主要介紹了JAVA 原型模式的的相關(guān)資料,文中講解非常細(xì)致,實(shí)例幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下

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

原型模式的工作原理很簡單:將一個(gè)原型對象傳給那個(gè)要發(fā)動(dòng)創(chuàng)建的對象,這個(gè)要發(fā)動(dòng)創(chuàng)建的對象通過請求原型對象拷貝自己來實(shí)現(xiàn)創(chuàng)建過程。

原型模式是一種“另類”的創(chuàng)建型模式,創(chuàng)建克隆對象的工廠就是原型類自身,工廠方法由克隆方法來實(shí)現(xiàn)。

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

 

角色

  • Prototype(抽象原型類):它是聲明克隆方法的接口,是所有具體原型類的公共父類,可以是抽象類也可以是接口,甚至還可以是具體實(shí)現(xiàn)類。
  • ConcretePrototype(具體原型類):它實(shí)現(xiàn)在抽象原型類中聲明的克隆方法,在克隆方法中返回自己的一個(gè)克隆對象。
  • Client(客戶類):讓一個(gè)原型對象克隆自身從而創(chuàng)建一個(gè)新的對象,在客戶類中只需要直接實(shí)例化或通過工廠方法等方式創(chuàng)建一個(gè)原型對象,再通過調(diào)用該對象的克隆方法即可得到多個(gè)相同的對象。由于客戶類針對抽象原型類Prototype編程,因此用戶可以根據(jù)需要選擇具體原型類,系統(tǒng)具有較好的可擴(kuò)展性,增加或更換具體原型類都很方便。

原型模式的核心在于如何實(shí)現(xiàn)克隆方法。

 

Java語言提供的clone()方法

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

需要注意的是能夠?qū)崿F(xiàn)克隆的Java類必須實(shí)現(xiàn)一個(gè) 標(biāo)識(shí)接口 Cloneable,表示這個(gè)Java類支持被復(fù)制。如果一個(gè)類沒有實(shí)現(xiàn)這個(gè)接口但是調(diào)用了clone()方法,Java編譯器將拋出一個(gè) CloneNotSupportedException 異常。

 

代碼演示―克隆羊

具體原型類:

//實(shí)現(xiàn)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;
  }
}

客戶端創(chuàng)建并克隆原型對象:

      //創(chuàng)建原型對象
      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設(shè)計(jì)模式---原型模式你了解嗎

結(jié)論

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

看一眼 Object#clone 方法

protected native Object clone() throws CloneNotSupportedException;

這是一個(gè) native 關(guān)鍵字修飾的方法

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

  • 對任何對象x,都有 x.clone() != x,即克隆對象與原型對象不是同一個(gè)對象;
  • 對任何對象x,都有 x.clone().getClass() == x.getClass(),即克隆對象與原型對象的類型一樣;
  • 如果對象x的 equals() 方法定義恰當(dāng),那么 x.clone().equals(x) 應(yīng)該成立。
  • 為了獲取對象的一份拷貝,我們可以直接利用Object類的clone()方法,具體步驟如下:

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

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

派生類需實(shí)現(xiàn)Cloneable接口。

此時(shí),Object類相當(dāng)于抽象原型類,所有實(shí)現(xiàn)了Cloneable接口的類相當(dāng)于具體原型類。

 

深淺拷貝

pig類:

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

sheep類:

//實(shí)現(xiàn)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;
  }
}

客戶端進(jìn)行克隆:

public class test
{
  @Test
  public void test() throws CloneNotSupportedException {
      //創(chuàng)建原型對象
      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設(shè)計(jì)模式---原型模式你了解嗎

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

深淺拷貝探討

淺克隆:

  • 在淺克隆中,如果原型對象的成員變量是值類型,將復(fù)制一份給克隆對象;如果原型對象的成員變量是引用類型,則將引用對象的地址復(fù)制一份給克隆對象,也就是說原型對象和克隆對象的成員變量指向相同的內(nèi)存地址。
  • 簡單來說,在淺克隆中,當(dāng)對象被復(fù)制時(shí)只復(fù)制它本身和其中包含的值類型的成員變量,而引用類型的成員對象并沒有復(fù)制。
  • 在Java語言中,通過覆蓋Object類的clone()方法可以實(shí)現(xiàn)淺克隆

深克隆:

  • 在深克隆中,無論原型對象的成員變量是值類型還是引用類型,都將復(fù)制一份給克隆對象,深克隆將原型對象的所有引用對象也復(fù)制一份給克隆對象。
  • 簡單來說,在深克隆中,除了對象本身被復(fù)制外,對象所包含的所有成員變量也將復(fù)制。
  • 在Java語言中,如果需要實(shí)現(xiàn)深克隆,可以通過序列化(Serialization)等方式來實(shí)現(xiàn)。需要注意的是能夠?qū)崿F(xiàn)序列化的對象其類必須實(shí)現(xiàn)Serializable接口,否則無法實(shí)現(xiàn)序列化操作。

實(shí)現(xiàn)深克隆的方式一 : 手動(dòng)對引用對象進(jìn)行克隆

Pig類首先需要實(shí)現(xiàn)克隆即可,并重寫clone方法:

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

sheep類:

//實(shí)現(xiàn)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設(shè)計(jì)模式---原型模式你了解嗎

實(shí)現(xiàn)深克隆的方式二 :序列化

對象可以序列化的前提是實(shí)現(xiàn)了Serializable接口,這里Sheep和Pig都需要實(shí)現(xiàn)該接口

pig類:

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

sheep類:

//實(shí)現(xiàn)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構(gòu)造函數(shù)的參數(shù)是,將對象流寫入到哪里
      ObjectOutputStream oot=new ObjectOutputStream(baot);
        oot.writeObject(this);
        //將序列化的對象從流中讀取出來
      ByteArrayInputStream bait=new ByteArrayInputStream(baot.toByteArray());
      ObjectInputStream oit=new ObjectInputStream(bait);
      return (Sheep) oit.readObject();
  }
}

JAVA設(shè)計(jì)模式---原型模式你了解嗎

 

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

餓漢式單例模式如下:

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

可以看到,通過原型模式,我們把單例模式給破壞了,現(xiàn)在有兩個(gè)對象了

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

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

 

優(yōu)缺點(diǎn)

原型模式的主要優(yōu)點(diǎn)如下:

  • 當(dāng)創(chuàng)建新的對象實(shí)例較為復(fù)雜時(shí),使用原型模式可以簡化對象的創(chuàng)建過程,通過復(fù)制一個(gè)已有實(shí)例可以提高新實(shí)例的創(chuàng)建效率。
  • 擴(kuò)展性較好,由于在原型模式中提供了抽象原型類,在客戶端可以針對抽象原型類進(jìn)行編程,而將具體原型類寫在配置文件中,增加或減少產(chǎn)品類對原有系統(tǒng)都沒有任何影響。
  • 原型模式提供了簡化的創(chuàng)建結(jié)構(gòu),工廠方法模式常常需要有一個(gè)與產(chǎn)品類等級結(jié)構(gòu)相同的工廠等級結(jié)構(gòu),而原型模式就不需要這樣,原型模式中產(chǎn)品的復(fù)制是通過封裝在原型類中的克隆方法實(shí)現(xiàn)的,無須專門的工廠類來創(chuàng)建產(chǎn)品。
  • 可以使用深克隆的方式保存對象的狀態(tài),使用原型模式將對象復(fù)制一份并將其狀態(tài)保存起來,以便在需要的時(shí)候使用(如恢復(fù)到某一歷史狀態(tài)),可輔助實(shí)現(xiàn)撤銷操作。

原型模式的主要缺點(diǎn)如下:

  • 需要為每一個(gè)類配備一個(gè)克隆方法,而且該克隆方法位于一個(gè)類的內(nèi)部,當(dāng)對已有的類進(jìn)行改造時(shí),需要修改源代碼,違背了“開閉原則”。
  • 在實(shí)現(xiàn)深克隆時(shí)需要編寫較為復(fù)雜的代碼,而且當(dāng)對象之間存在多重的嵌套引用時(shí),為了實(shí)現(xiàn)深克隆,每一層對象對應(yīng)的類都必須支持深克隆,實(shí)現(xiàn)起來可能會(huì)比較麻煩。 適用場景
  • 創(chuàng)建新對象成本較大(如初始化需要占用較長的時(shí)間,占用太多的CPU資源或網(wǎng)絡(luò)資源),新的對象可以通過原型模式對已有對象進(jìn)行復(fù)制來獲得,如果是相似對象,則可以對其成員變量稍作修改。
  • 如果系統(tǒng)要保存對象的狀態(tài),而對象的狀態(tài)變化很小,或者對象本身占用內(nèi)存較少時(shí),可以使用原型模式配合備忘錄模式來實(shí)現(xiàn)。
  • 需要避免使用分層次的工廠類來創(chuàng)建分層次的對象,并且類的實(shí)例對象只有一個(gè)或很少的幾個(gè)組合狀態(tài),通過復(fù)制原型對象得到新實(shí)例可能比使用構(gòu)造函數(shù)創(chuàng)建一個(gè)新實(shí)例更加方便。

 

原型模式在Spring中的應(yīng)用場景

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

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

 

總結(jié)

JAVA設(shè)計(jì)模式---原型模式你了解嗎

本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關(guān)注服務(wù)器之家的更多內(nèi)容!

原文鏈接:https://blog.csdn.net/m0_53157173/article/details/120015362

延伸 · 閱讀

精彩推薦
  • Java教程升級IDEA后Lombok不能使用的解決方法

    升級IDEA后Lombok不能使用的解決方法

    最近看到提示IDEA提示升級,尋思已經(jīng)有好久沒有升過級了。升級完畢重啟之后,突然發(fā)現(xiàn)好多錯(cuò)誤,本文就來介紹一下如何解決,感興趣的可以了解一下...

    程序猿DD9332021-10-08
  • Java教程Java使用SAX解析xml的示例

    Java使用SAX解析xml的示例

    這篇文章主要介紹了Java使用SAX解析xml的示例,幫助大家更好的理解和學(xué)習(xí)使用Java,感興趣的朋友可以了解下...

    大行者10067412021-08-30
  • Java教程Java BufferWriter寫文件寫不進(jìn)去或缺失數(shù)據(jù)的解決

    Java BufferWriter寫文件寫不進(jìn)去或缺失數(shù)據(jù)的解決

    這篇文章主要介紹了Java BufferWriter寫文件寫不進(jìn)去或缺失數(shù)據(jù)的解決方案,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望...

    spcoder14552021-10-18
  • Java教程小米推送Java代碼

    小米推送Java代碼

    今天小編就為大家分享一篇關(guān)于小米推送Java代碼,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧...

    富貴穩(wěn)中求8032021-07-12
  • Java教程20個(gè)非常實(shí)用的Java程序代碼片段

    20個(gè)非常實(shí)用的Java程序代碼片段

    這篇文章主要為大家分享了20個(gè)非常實(shí)用的Java程序片段,對java開發(fā)項(xiàng)目有所幫助,感興趣的小伙伴們可以參考一下 ...

    lijiao5352020-04-06
  • Java教程xml與Java對象的轉(zhuǎn)換詳解

    xml與Java對象的轉(zhuǎn)換詳解

    這篇文章主要介紹了xml與Java對象的轉(zhuǎn)換詳解的相關(guān)資料,需要的朋友可以參考下...

    Java教程網(wǎng)2942020-09-17
  • Java教程Java8中Stream使用的一個(gè)注意事項(xiàng)

    Java8中Stream使用的一個(gè)注意事項(xiàng)

    最近在工作中發(fā)現(xiàn)了對于集合操作轉(zhuǎn)換的神器,java8新特性 stream,但在使用中遇到了一個(gè)非常重要的注意點(diǎn),所以這篇文章主要給大家介紹了關(guān)于Java8中S...

    阿杜7482021-02-04
  • Java教程Java實(shí)現(xiàn)搶紅包功能

    Java實(shí)現(xiàn)搶紅包功能

    這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)搶紅包功能,采用多線程模擬多人同時(shí)搶紅包,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙...

    littleschemer13532021-05-16
主站蜘蛛池模板: 中国hdxxxx护士爽在线观看 | 日韩中文字幕三区 | 久久美女免费视频 | 欧美精品一区二区久久久 | 国产羞羞视频在线观看免费应用 | 国产成人综合在线视频 | 久久色网站 | 一级大片一级一大片 | 高清av免费 | 九九热在线视频观看这里只有精品 | 亚州欧美在线 | 欧美亚洲国产成人 | 亚洲精品v天堂中文字幕 | 超碰九色 | 成年免费视频黄网站在线观看 | 国产精品久久久久久久久久iiiii | 午夜偷拍视频 | 精品呦女| 美女黄色影院 | 欧美性生活xxxxx | 久久精品国产一区二区 | 日韩av在线网址 | 久久国产精品小视频 | 涩涩屋av| 中文字幕在线观看成人 | 亚洲国产馆 | 色羞羞| 日本中文字幕电影在线观看 | 黄色av片在线观看 | 亚洲网视频 | av在线免费看片 | 亚洲午夜影院在线观看 | 久久久久久久久久91 | 好吊色37pao在线观看 | 国产资源在线视频 | 欧美视频99 | 综合国产一区 | 黄色18网站 | 成人福利在线免费观看 | 一级毛片免费高清视频 | 日韩黄色av网站 |