最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

 更新時(shí)間:2021年09月03日 10:19:52   作者:大忽悠愛(ài)忽悠  
這篇文章主要介紹了JAVA 原型模式的的相關(guān)資料,文中講解非常細(xì)致,實(shí)例幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下

介紹

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

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

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

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

角色

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

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

Java語(yǔ)言提供的clone()方法

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

需要注意的是能夠?qū)崿F(xiàn)克隆的Java類必須實(shí)現(xiàn)一個(gè) 標(biāo)識(shí)接口 Cloneable,表示這個(gè)Java類支持被復(fù)制。如果一個(gè)類沒(méi)有實(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;
    //重寫(xiě)Object的clone方法
    @Override
    protected Object clone() throws CloneNotSupportedException 
    {
        Sheep sheep=null;
        sheep=(Sheep)super.clone();
        return sheep;
    }
}

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

        //創(chuàng)建原型對(duì)象
        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);

在這里插入圖片描述

結(jié)論

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

看一眼 Object#clone 方法

protected native Object clone() throws CloneNotSupportedException;

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

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

  • 對(duì)任何對(duì)象x,都有 x.clone() != x,即克隆對(duì)象與原型對(duì)象不是同一個(gè)對(duì)象;
  • 對(duì)任何對(duì)象x,都有 x.clone().getClass() == x.getClass(),即克隆對(duì)象與原型對(duì)象的類型一樣;
  • 如果對(duì)象x的 equals() 方法定義恰當(dāng),那么 x.clone().equals(x) 應(yīng)該成立。
  • 為了獲取對(duì)象的一份拷貝,我們可以直接利用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;
    //重寫(xiě)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)建原型對(duì)象
        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());
    }
}

在這里插入圖片描述

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

深淺拷貝探討

淺克?。?/strong>

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

深克?。?/strong>

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

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

Pig類首先需要實(shí)現(xiàn)克隆即可,并重寫(xiě)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;
    //重寫(xiě)Object的clone方法
    @Override
    protected Sheep clone() throws CloneNotSupportedException
    {
        Sheep sheep=null;
        sheep=(Sheep)super.clone();
        sheep.pig=(Pig)sheep.pig.clone();
        return sheep;
    }
}

在這里插入圖片描述

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

對(duì)象可以序列化的前提是實(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 {
        //先將要序列化的對(duì)象寫(xiě)入流中
        ByteArrayOutputStream baot=new ByteArrayOutputStream();
        //ObjectOutputStream構(gòu)造函數(shù)的參數(shù)是,將對(duì)象流寫(xiě)入到哪里
        ObjectOutputStream oot=new ObjectOutputStream(baot);
          oot.writeObject(this);
          //將序列化的對(duì)象從流中讀取出來(lái)
        ByteArrayInputStream bait=new ByteArrayInputStream(baot.toByteArray());
        ObjectInputStream oit=new ObjectInputStream(bait);
        return (Sheep) oit.readObject();
    }
}

在這里插入圖片描述

原型模式對(duì)單例模式的破壞

餓漢式單例模式如下:

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();
    }
}

使用反射獲取對(duì)象,測(cè)試如下

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

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

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

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

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

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

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

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

總結(jié)

在這里插入圖片描述

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

相關(guān)文章

  • Java8的Stream()與ParallelStream()的區(qū)別說(shuō)明

    Java8的Stream()與ParallelStream()的區(qū)別說(shuō)明

    這篇文章主要介紹了Java8的Stream()與ParallelStream()的區(qū)別說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • 使用React和springboot做前后端分離項(xiàng)目的步驟方式

    使用React和springboot做前后端分離項(xiàng)目的步驟方式

    這篇文章主要介紹了使用React和springboot做前后端分離項(xiàng)目的步驟方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-08-08
  • JAVA多種方法實(shí)現(xiàn)字符串反轉(zhuǎn)

    JAVA多種方法實(shí)現(xiàn)字符串反轉(zhuǎn)

    大家好,本篇文章主要講的是JAVA多種方法實(shí)現(xiàn)字符串反轉(zhuǎn),感興趣的同學(xué)趕快來(lái)看一看吧,對(duì)你有幫助的話記得收藏一下,方便下次瀏覽
    2022-01-01
  • Spring MVC--攔截器實(shí)現(xiàn)和用戶登陸例子

    Spring MVC--攔截器實(shí)現(xiàn)和用戶登陸例子

    本文主要介紹了Spring MVC--攔截器實(shí)現(xiàn)和用戶登陸例子,具有很好的參考價(jià)值,下面跟著小編一起來(lái)看下吧
    2017-03-03
  • 關(guān)于shiro中部分SpringCache失效問(wèn)題的解決方法

    關(guān)于shiro中部分SpringCache失效問(wèn)題的解決方法

    這篇文章主要給大家介紹了關(guān)于shiro中部分SpringCache失效問(wèn)題的解決方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2018-07-07
  • MyBatis的五種批量插入詳解

    MyBatis的五種批量插入詳解

    這篇文章主要介紹了MyBatis的五種批量插入詳解,MyBatis是一款半自動(dòng)的ORM持久層框架,具有較高的SQL靈活性,支持高級(jí)映射(一對(duì)一,一對(duì)多),動(dòng)態(tài)SQL,延遲加載和緩存等特性,但它的數(shù)據(jù)庫(kù)無(wú)關(guān)性較低,需要的朋友可以參考下
    2023-08-08
  • java通過(guò)信號(hào)量實(shí)現(xiàn)限流的示例

    java通過(guò)信號(hào)量實(shí)現(xiàn)限流的示例

    本文主要介紹了java通過(guò)信號(hào)量實(shí)現(xiàn)限流的示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-06-06
  • 深入Java冒泡排序與選擇排序的區(qū)別詳解

    深入Java冒泡排序與選擇排序的區(qū)別詳解

    本篇文章是對(duì)Java冒泡排序與選擇排序的區(qū)別進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
    2013-05-05
  • 使用Java實(shí)現(xiàn)5種負(fù)載均衡算法實(shí)例

    使用Java實(shí)現(xiàn)5種負(fù)載均衡算法實(shí)例

    負(fù)載均衡指由多臺(tái)服務(wù)器以對(duì)稱的方式組成一個(gè)服務(wù)器集合,每臺(tái)服務(wù)器都具有等價(jià)的地位,都可以單獨(dú)對(duì)外提供服務(wù)而無(wú)須其他服務(wù)器的輔助,這篇文章主要給大家介紹了關(guān)于使用Java實(shí)現(xiàn)5種負(fù)載均衡算法的相關(guān)資料,需要的朋友可以參考下
    2021-09-09
  • idea中創(chuàng)建多module的maven工程的方法

    idea中創(chuàng)建多module的maven工程的方法

    這篇文章主要介紹了idea中創(chuàng)建多module的maven工程的方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-10-10

最新評(píng)論

柳江县| 庄浪县| 河间市| 中牟县| 武夷山市| 通山县| 赣榆县| 河北区| 乐安县| 金塔县| 林西县| 横峰县| 沂南县| 祁东县| 岗巴县| 卓尼县| 巴彦县| 汪清县| 承德市| 东乌| 孟州市| 始兴县| 遂川县| 东辽县| 黄山市| 前郭尔| 凤冈县| 敦化市| 华池县| 绩溪县| 洛浦县| 武宁县| 临桂县| 长宁区| 罗定市| 呼伦贝尔市| 洪洞县| 东阿县| 仁寿县| 酒泉市| 武安市|