(4)spring常用模式--------原型模式

原型模式就是從一個(gè)對(duì)象再創(chuàng)建另外一個(gè)可定制的對(duì)象返十, 而且不需要知道任何創(chuàng)建的細(xì)節(jié)策肝。
所謂原型模式肛捍, 就是 Java 中的克隆技術(shù), 以某個(gè)對(duì)象為原型之众。 復(fù)制出新的對(duì)象拙毫。 顯然新的對(duì)象具備原型對(duì)象的特點(diǎn), 效率高(避免了重新執(zhí)行構(gòu)造過程步驟)

在介紹原型模式之前棺禾,需要介紹淺拷貝和深拷貝的概念

1.淺拷貝和深拷貝的特點(diǎn)

淺拷貝

  • ①對(duì)于數(shù)據(jù)類型是基本數(shù)據(jù)類型的成員變量缀蹄,淺拷貝會(huì)直接進(jìn)行值傳遞,也就是將該屬性值復(fù)制一份給新的對(duì)象。
  • ②對(duì)于數(shù)據(jù)類型是引用數(shù)據(jù)類型的成員變量缺前,比如說成員變量是某個(gè)數(shù)組蛀醉、某個(gè)類的對(duì)象等,那么淺拷貝會(huì)進(jìn)行引用傳遞诡延,也就是只是將該成員變量的引用值(內(nèi)存地址)復(fù)制一份給新的對(duì)象滞欠。因?yàn)閷?shí)際上兩個(gè)對(duì)象的該成員變量都指向同一個(gè)實(shí)例。在這種情況下肆良,在一個(gè)對(duì)象中修改該成員變量會(huì)影響到另一個(gè)對(duì)象的該成員變量值。

深拷貝:

  • ①復(fù)制對(duì)象的所有基本數(shù)據(jù)類型的成員變量值
  • ②為所有引用數(shù)據(jù)類型的成員變量申請(qǐng)存儲(chǔ)空間逸绎,并復(fù)制每個(gè)引用數(shù)據(jù)類型成員變量所引用的對(duì)象惹恃,直到該對(duì)象可達(dá)的所有對(duì)象。也就是說棺牧,對(duì)象進(jìn)行深拷貝要對(duì)整個(gè)對(duì)象圖進(jìn)行拷貝巫糙!

總結(jié)
深拷貝對(duì)引用數(shù)據(jù)類型的成員變量的對(duì)象圖中所有的對(duì)象都開辟了內(nèi)存空間;而淺拷貝只是傳遞地址指向颊乘,新的對(duì)象并沒有對(duì)引用數(shù)據(jù)類型創(chuàng)建內(nèi)存空間

2.原型模式的淺拷貝和深拷貝的實(shí)現(xiàn)方式

  • 淺拷貝
     通過拷貝構(gòu)造方法實(shí)現(xiàn)淺拷貝
     通過重寫clone()方法進(jìn)行淺拷貝
  • 深拷貝
     通過重寫clone方法來實(shí)現(xiàn)深拷貝
     通過對(duì)象序列化實(shí)現(xiàn)深拷貝

接下來直接介紹淺拷貝和深拷貝的具體實(shí)現(xiàn)

在此之前参淹,先給出原型模式的uml圖


原型模式.png

3.原型模式的淺拷貝

淺度克隆目標(biāo)的引用對(duì)象

/**
 * @Project: spring
 * @description:  淺度克隆目標(biāo)的引用對(duì)象
 * @author: sunkang
 * @create: 2018-09-02 10:48
 * @ModificationHistory who      when       What
 **/
public class CloneableTarget   {

    public  String cloneName;

    public String cloneClass;
    
    public CloneableTarget( String cloneName,String cloneClass) {
        this.cloneName = cloneName;
        this.cloneClass = cloneClass;
    }
}

淺度克隆的對(duì)象的兩種實(shí)現(xiàn)方式

/**
 * @Project: spring
 * @description:  克隆對(duì)象的淺拷貝
 *   1.通過構(gòu)造方法來實(shí)現(xiàn)淺度拷貝
 *   2.通過clone()方法來實(shí)現(xiàn)淺度拷貝
 * @author: sunkang
 * @create: 2018-09-02 10:47
 * @ModificationHistory who      when       What
 **/
public class Prototype implements  Cloneable {

    public String name ;

    //拷貝的引用類型的成員變量
    public  CloneableTarget cloneableTarget;

    public Prototype(){

    }
    //1.通過構(gòu)造方法來實(shí)現(xiàn)淺度拷貝
    public Prototype(Prototype prototype) {
        this.name = prototype.name;
        this.cloneableTarget = prototype.cloneableTarget;
    }
    //2.通過clone()方法來實(shí)現(xiàn)淺度拷貝
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

淺克隆的測(cè)試

/**
 * @Project: spring
 * @description: 淺度克隆對(duì)象的測(cè)試
 *
 * @author: sunkang
 * @create: 2018-09-02 10:51
 * @ModificationHistory who      when       What
 **/
public class CloneTest  {
    public static void main(String[] args) {
        Prototype  p = new Prototype();
        p.name="kang";
        p.cloneableTarget = new CloneableTarget("clone","CloneableTarget");
        System.out.println("原有的對(duì)象:"+p);
        System.out.println("原有的值對(duì)象引用:"+p.name.hashCode());
        System.out.println("原有的引用類型對(duì)象:"+p.cloneableTarget);
        try {
            //方式一 :通過重寫clone()方法進(jìn)行淺拷貝
            Prototype clonePrototype = (Prototype) p.clone();
            System.out.println("重寫clone()克隆的對(duì)象:"+clonePrototype);
            System.out.println("重寫clone()克隆的值對(duì)象引用:"+p.name.hashCode());
            System.out.println("重寫clone()克隆的引用類型對(duì)象:"+ clonePrototype.cloneableTarget);

            //通過修改引用對(duì)象String類型的值,發(fā)現(xiàn)原有的對(duì)象的值沒有發(fā)生改變乏悄,因?yàn)镾tring對(duì)象是不可變對(duì)象浙值,放在常量池中的,無法修改的
            //String 可以比較特殊檩小,可以看做是值傳遞
            clonePrototype.name ="sun";
            System.out.println("原有對(duì)象的name:"+p.name);
            System.out.println("修改過的clone對(duì)象的name:"+clonePrototype.name);

            //方式二: 通過拷貝構(gòu)造方法實(shí)現(xiàn)淺拷貝
            Prototype  constructClone=   new Prototype(p);
            System.out.println("構(gòu)造方法克隆的對(duì)象:"+constructClone);
            System.out.println("構(gòu)造方法克隆的值對(duì)象引用:"+constructClone.name.hashCode());
            System.out.println("構(gòu)造方法克隆的引用類型對(duì)象:"+ constructClone.cloneableTarget);
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
    }
}

測(cè)試結(jié)果 : 可以發(fā)現(xiàn)引用類型的目標(biāo)對(duì)象為同一個(gè)引用开呐,string 對(duì)象可以看做是值傳遞,string對(duì)象是不可變的规求,克隆對(duì)象修改后的值對(duì)原有對(duì)象的值沒有影響

淺克隆測(cè)試結(jié)果.png

4.原型模式的深拷貝

深度拷貝的目標(biāo)引用對(duì)象

/**
 * 深度拷貝的目標(biāo)引用對(duì)象
 */
public class DeepCloneableTarget implements Serializable,Cloneable {

    private  String cloneName;

    private String cloneClass;


    public DeepCloneableTarget(String cloneName, String cloneClass) {
        this.cloneName = cloneName;
        this.cloneClass = cloneClass;
    }

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

深度拷貝的實(shí)現(xiàn)拷貝的兩種方式

/**
 * @Project: spring
 * @description: 深度拷貝的實(shí)現(xiàn)拷貝的兩種方式
 * @author: sunkang
 * @create: 2018-09-02 11:19
 * @ModificationHistory who      when       What
 **/
public class DeepPrototype implements Serializable,Cloneable {

    public String name ;

    public  DeepCloneableTarget deepCloneableTarget;

    public DeepPrototype(){

    }
    //方式1 :通過重寫clone方法來實(shí)現(xiàn)深拷貝  (引用對(duì)象多筐付,這種方法比較繁瑣)
    @Override
    protected Object clone() throws CloneNotSupportedException {
        Object deep = null;
        try {
            deep = super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        DeepPrototype  deepPrototype = (DeepPrototype) deep;
        deepPrototype.deepCloneableTarget = (DeepCloneableTarget) deepPrototype.deepCloneableTarget.clone();
        return deepPrototype;
    }

    //方式2: 通過對(duì)象序列化實(shí)現(xiàn)深拷貝 (推薦)
    public Object deepClone(){
        ByteArrayOutputStream bos = null;
        ObjectOutputStream oos = null;
        try {
             bos = new ByteArrayOutputStream();
             oos = new ObjectOutputStream(bos);
             oos.writeObject(this);

            ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(bis);
            return  ois.readObject();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }finally {
            if(oos !=null){
                try {
                    oos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(bos !=null){
                try {
                    bos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            //輸入流關(guān)閉省略
        }
        return null;
    }
}

深度拷貝的測(cè)試

/**
 * @Project: spring
 * @description:  深度拷貝的測(cè)試
 * @author: sunkang
 * @create: 2018-09-02 11:38
 * @ModificationHistory who      when       What
 **/
public class DeepCloneTest {

    public static void main(String[] args) {
        DeepPrototype p = new DeepPrototype();
        p.name="kang";

        p.deepCloneableTarget = new DeepCloneableTarget("clone","CloneableTarget");
        System.out.println("原有的對(duì)象:"+p);
        System.out.println("原有的值對(duì)象引用:"+p.name.hashCode());
        System.out.println("原有的引用類型對(duì)象:"+p.deepCloneableTarget);

        try {
            //方式一 :通過重寫clone()方法進(jìn)行淺拷貝
            DeepPrototype clonePrototype = (DeepPrototype) p.clone();
            System.out.println("clone()方法克隆的對(duì)象:"+clonePrototype);
            System.out.println("clone()方法克隆的值對(duì)象引用:"+p.name.hashCode());
            System.out.println("clone()方法克隆的引用類型對(duì)象:"+ clonePrototype.deepCloneableTarget);

            //方式二:  通過對(duì)象序列化實(shí)現(xiàn)深拷貝
            DeepPrototype  serializableClone= (DeepPrototype) p.deepClone();
            System.out.println("序列化方法克隆的對(duì)象:"+serializableClone);
            System.out.println("構(gòu)序列化方法克隆的值對(duì)象引用:"+serializableClone.name.hashCode());
            System.out.println("序列化方法克隆的引用類型對(duì)象:"+ serializableClone.deepCloneableTarget);
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
    }
}

測(cè)試結(jié)果 :可以發(fā)現(xiàn)引用類型的成員變量的地址都是不一樣的了,說明實(shí)現(xiàn)了深度拷貝

深拷貝的測(cè)試結(jié)果.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末阻肿,一起剝皮案震驚了整個(gè)濱河市瓦戚,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌丛塌,老刑警劉巖较解,帶你破解...
    沈念sama閱讀 218,607評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異姨伤,居然都是意外死亡哨坪,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,239評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門乍楚,熙熙樓的掌柜王于貴愁眉苦臉地迎上來当编,“玉大人,你說我怎么就攤上這事徒溪》尥担” “怎么了金顿?”我有些...
    開封第一講書人閱讀 164,960評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長鲤桥。 經(jīng)常有香客問我揍拆,道長,這世上最難降的妖魔是什么茶凳? 我笑而不...
    開封第一講書人閱讀 58,750評(píng)論 1 294
  • 正文 為了忘掉前任嫂拴,我火速辦了婚禮,結(jié)果婚禮上贮喧,老公的妹妹穿的比我還像新娘筒狠。我一直安慰自己,他們只是感情好箱沦,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,764評(píng)論 6 392
  • 文/花漫 我一把揭開白布辩恼。 她就那樣靜靜地躺著,像睡著了一般谓形。 火紅的嫁衣襯著肌膚如雪灶伊。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,604評(píng)論 1 305
  • 那天寒跳,我揣著相機(jī)與錄音聘萨,去河邊找鬼。 笑死冯袍,一個(gè)胖子當(dāng)著我的面吹牛匈挖,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播康愤,決...
    沈念sama閱讀 40,347評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼儡循,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了征冷?” 一聲冷哼從身側(cè)響起择膝,我...
    開封第一講書人閱讀 39,253評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎检激,沒想到半個(gè)月后肴捉,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,702評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡叔收,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,893評(píng)論 3 336
  • 正文 我和宋清朗相戀三年齿穗,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片饺律。...
    茶點(diǎn)故事閱讀 40,015評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡窃页,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情脖卖,我是刑警寧澤乒省,帶...
    沈念sama閱讀 35,734評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站畦木,受9級(jí)特大地震影響袖扛,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜十籍,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,352評(píng)論 3 330
  • 文/蒙蒙 一蛆封、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧妓雾,春花似錦娶吞、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,934評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽机断。三九已至楷拳,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,052評(píng)論 1 270
  • 我被黑心中介騙來泰國打工酿傍, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留砾莱,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,216評(píng)論 3 371
  • 正文 我出身青樓饲漾,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子坤按,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,969評(píng)論 2 355