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

Java設(shè)計(jì)模式之原型模式詳解

 更新時(shí)間:2021年05月06日 11:40:24   作者:小小魚(yú)兒小小林  
這篇文章主要介紹了Java設(shè)計(jì)模式之原型模式詳解,文中有非常詳細(xì)的代碼示例,對(duì)正在學(xué)習(xí)java的小伙伴們有非常好的幫助,需要的朋友可以參考下

一、前言

原型模式是一種比較簡(jiǎn)單的模式,也非常容易理解,實(shí)現(xiàn)一個(gè)接口,重寫(xiě)一個(gè)方法即完成了原型模式。在實(shí)際應(yīng)用中,原型模式很少單獨(dú)出現(xiàn)。經(jīng)常與其他模式混用,他的原型類(lèi)Prototype也常用抽象類(lèi)來(lái)替代。

該模式的思想就是將一個(gè)對(duì)象作為原型,對(duì)其進(jìn)行復(fù)制、克隆,產(chǎn)生一個(gè)和原對(duì)象類(lèi)似的新對(duì)象。在Java中,復(fù)制對(duì)象是通過(guò)clone()實(shí)現(xiàn)的,先創(chuàng)建一個(gè)原型類(lèi),通過(guò)實(shí)現(xiàn)Cloneable 接口

public class Prototype implements Cloneable {  
 
		public Object clone() throws CloneNotSupportedException {  
			Prototype proto = (Prototype) super.clone();  
			return proto;  
		}  
	}

只需要實(shí)現(xiàn)Cloneable接口,覆寫(xiě)clone方法,此處clone方法可以改成任意的名稱(chēng),因?yàn)镃loneable接口是個(gè)空接口,你可以任意定義實(shí)現(xiàn)類(lèi)的方法名,如cloneA或者cloneB,因?yàn)榇颂幍闹攸c(diǎn)是super.clone()這句話(huà),super.clone()調(diào)用的是Object的clone()方法,而在Object類(lèi)中,clone()是native的,說(shuō)明這個(gè)方法實(shí)現(xiàn)并不是使用java語(yǔ)言,是底層C實(shí)現(xiàn)阿達(dá)

至于cloneA或者cloneB名字可以任意取,是因?yàn)橐阒鲃?dòng)去調(diào)用的,所以你名字取成什么,你調(diào)用的時(shí)候就調(diào)用該名字就可以了

二、優(yōu)點(diǎn)及適用場(chǎng)景

使用原型模式創(chuàng)建對(duì)象比直接new一個(gè)對(duì)象在性能上要好的多,因?yàn)樯厦嫖乙蔡岬竭^(guò),Object類(lèi)的clone()是native的,它直接操作內(nèi)存中的二進(jìn)制流,特別是復(fù)制大對(duì)象時(shí),性能的差別非常明顯。

使用原型模式的另一個(gè)好處是簡(jiǎn)化對(duì)象的創(chuàng)建,使得創(chuàng)建對(duì)象就像我們?cè)诰庉嬑臋n時(shí)的復(fù)制粘貼一樣簡(jiǎn)單。

因?yàn)橐陨蟽?yōu)點(diǎn),所以在需要重復(fù)地創(chuàng)建相似對(duì)象時(shí)可以考慮使用原型模式。比如需要在一個(gè)循環(huán)體內(nèi)創(chuàng)建對(duì)象,假如對(duì)象創(chuàng)建過(guò)程比較復(fù)雜或者循環(huán)次數(shù)很多的話(huà),使用原型模式不但可以簡(jiǎn)化創(chuàng)建過(guò)程,而且可以使系統(tǒng)的整體性能提高很多。

三、原型模式的注意事項(xiàng)

使用原型模式復(fù)制對(duì)象不會(huì)調(diào)用類(lèi)的構(gòu)造方法。因?yàn)閷?duì)象的復(fù)制是通過(guò)調(diào)用Object類(lèi)的clone()來(lái)完成的,它直接在內(nèi)存中復(fù)制數(shù)據(jù),因此不會(huì)調(diào)用到類(lèi)的構(gòu)造方法。不但構(gòu)造方法中的代碼不會(huì)執(zhí)行,甚至連訪問(wèn)權(quán)限都對(duì)原型模式無(wú)效。

說(shuō)到這里,就得順便提一下單例模式,在單例模式中,只要將構(gòu)造方法的訪問(wèn)權(quán)限設(shè)置為private型,就可以實(shí)現(xiàn)單例。但是clone方法直接無(wú)視構(gòu)造方法的權(quán)限,所以,單例模式與原型模式是沖突的,在使用時(shí)要特別注意。

四、淺復(fù)制和深復(fù)制

另外還得知道兩個(gè)特別重要的概念 : 淺復(fù)制   深復(fù)制

淺復(fù)制:將一個(gè)對(duì)象復(fù)制后,基本數(shù)據(jù)類(lèi)型的變量都會(huì)重新創(chuàng)建,而數(shù)組、容器對(duì)象、引用對(duì)象等都不會(huì)拷貝,指向的還是原對(duì)象所指向的地址。淺拷貝實(shí)現(xiàn) Cloneable,重寫(xiě)clone方法

深復(fù)制:將一個(gè)對(duì)象復(fù)制后,不論是基本數(shù)據(jù)類(lèi)型還有引用類(lèi)型,都是重新創(chuàng)建的。簡(jiǎn)單來(lái)說(shuō),就是深復(fù)制進(jìn)行了完全徹底的復(fù)制,而淺復(fù)制不徹底。深拷貝是通過(guò)實(shí)現(xiàn) Serializable 讀取二進(jìn)制流

五、淺復(fù)制demo演示

首先我們創(chuàng)建一個(gè)抽象原型類(lèi) Animal.class,實(shí)現(xiàn)了Cloneable接口,并且重寫(xiě)了clone方法

package cn.zygxsq.design.module.prototypePattern;
 
/**
 * Created by yjl on 2021/4/30.
 * 動(dòng)物類(lèi)
 * 原型模式:博文介紹鏈接:https://blog.csdn.net/qq_27471405/article/details/116309878
 */
public abstract class Animal implements Cloneable{
    private String id;
    public String name;
 
    abstract void shout();
 
    public String getId() {
        return id;
    }
 
    public void setId(String id) {
        this.id = id;
    }
 
 
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
    /**
     * 淺復(fù)制
     */
    public Object clone() throws CloneNotSupportedException {
        Animal clone = (Animal) super.clone();
        return clone;
    }
}

再創(chuàng)建兩個(gè)實(shí)現(xiàn)類(lèi)

Dog.class 和Cat.class

package cn.zygxsq.design.module.prototypePattern;
 
/**
 * Created by yjl on 2021/4/30.
 */
public class Dog extends Animal {
    public Dog(){
        name = "狗狗";
    }
 
    @Override
    public void shout() {
        System.out.println("我的叫聲是:汪汪汪");
    }
}
package cn.zygxsq.design.module.prototypePattern;
 
/**
 * Created by yjl on 2021/4/30.
 */
public class Cat extends Animal {
    public Cat(){
        name = "貓貓";
    }
 
    @Override
    public void shout() {
        System.out.println("我的叫聲是:喵喵喵");
    }
}

然后創(chuàng)建一個(gè)數(shù)據(jù)緩存類(lèi),用戶(hù)存儲(chǔ)從數(shù)據(jù)庫(kù)中獲取到的大對(duì)象數(shù)據(jù)或者曾經(jīng)使用過(guò)的大對(duì)象數(shù)據(jù)

以后下一次想要再次對(duì)這個(gè)對(duì)象數(shù)據(jù)操作的時(shí)候,直接從緩存里獲取并且clone一個(gè)

package cn.zygxsq.design.module.prototypePattern;
 
import com.google.common.collect.Maps;
import org.springframework.beans.factory.InitializingBean;
 
import java.util.HashMap;
import java.util.Hashtable;
import java.util.concurrent.ConcurrentMap;
 
/**
 * Created by yjl on 2021/4/30.
 * 緩存類(lèi) 用于加載一些數(shù)據(jù)庫(kù)的緩存的數(shù)據(jù)
 */
public class DataCache /*implements InitializingBean*/{
    //正常的情況是 實(shí)現(xiàn) InitializingBean ,用于web服務(wù)啟動(dòng)的時(shí)候加載數(shù)據(jù)
    // 這里測(cè)試由于不是web服務(wù),所以就模擬加載數(shù)據(jù)
 
    private static ConcurrentMap<String, Animal> animalCache = Maps.newConcurrentMap();
 
    public static Animal getAnimal(String id) throws Exception{
        Animal cache = animalCache.get(id);
        return (Animal) cache.clone();
    }
 
    public static void init(){
        Dog dog = new Dog();
        String dogid = "111";
        dog.setId(dogid);
        animalCache.put(dogid,dog);
 
        Dog dog2 = new Dog();
        String dogid2 = "222";
        dog2.setId(dogid2);
        animalCache.put(dogid2,dog2);
 
        Cat cat = new Cat();
        String catid = "333";
        cat.setId(catid);
        animalCache.put(catid,cat);
 
    }
}

最后咱們開(kāi)始測(cè)試

先是從數(shù)據(jù)庫(kù)里加載緩存,然后要從緩存里獲取數(shù)據(jù),并且的到的是一個(gè)個(gè)clone出來(lái)的對(duì)象

package cn.zygxsq.design.module.prototypePattern;
 
import com.alibaba.fastjson.JSON;
 
/**
 * Created by yjl on 2021/4/30.
 * 測(cè)試主類(lèi) 淺復(fù)制
 * 原型模式:博文介紹鏈接:https://blog.csdn.net/qq_27471405/article/details/116309878
 */
public class TestPrototype {
    public static void main(String[] args) {
        DataCache.init(); // 模擬加載數(shù)據(jù)到緩存中
 
        try {
            Animal animal = DataCache.getAnimal("111");
            System.out.println(animal.getName()+"---"+JSON.toJSONString(animal));
 
            Animal animal222 = DataCache.getAnimal("222");
            System.out.println(animal222.getName()+"---"+JSON.toJSONString(animal222));
 
            Animal animal333 = DataCache.getAnimal("333");
            System.out.println(animal333.getName()+"---"+JSON.toJSONString(animal333));
 
            animal.shout();
            animal222.shout();
            animal333.shout();
        } catch (Exception e) {
            e.printStackTrace();
        }
 
 
    }
}

運(yùn)行結(jié)果: 

小伙伴們看的時(shí)候,好像沒(méi)什么問(wèn)題,確實(shí)沒(méi)什么問(wèn)題,但是細(xì)細(xì)一看,還是有一定的問(wèn)題的

package cn.zygxsq.design.module.prototypePattern;
 
import com.alibaba.fastjson.JSON;
 
/**
 * Created by yjl on 2021/4/30.
 * 淺復(fù)制遇到的問(wèn)題
 */
public class TestCloneProblem {
 
    public static void main(String[] args) {
        //做完TestPrototype的main方法后,好像覺(jué)得淺復(fù)制沒(méi)有什么問(wèn)題
        //那么可以看一下下面的a1的name 和 克隆后的name指向的是同一個(gè)地址
        DataCache.init(); // 模擬加載數(shù)據(jù)到緩存中
 
        try {
            Animal a1 = DataCache.getAnimal("111");
            Animal a2 = (Animal)a1.clone();
            System.out.println(a1==a2);
            System.out.println(a1.name == a2.name);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
 
}

運(yùn)行結(jié)果:

大家踩一下 a1的name 和 克隆后的name是什么樣的關(guān)系呢

大家可以看到,a1的name和a2的name是一樣的,由于他們的類(lèi)型是String,所以他們指向的是同一個(gè)地址,名稱(chēng)為“狗狗”的引用地址,大概的樣子可以看下圖

那怎么樣才能不讓a1.name 和a2.name不相同呢,也就是完完全全的復(fù)制,這個(gè)就得用到深復(fù)制了

深復(fù)制其實(shí)用到的就是流復(fù)制

可以在clone()的方法定義一個(gè)深復(fù)制的方法,比如deepClone()

六、深復(fù)制demo演示

記住,深復(fù)制的時(shí)候,方法一定得實(shí)現(xiàn)可序列化,Serializable

package cn.zygxsq.design.module.prototypePattern;
 
import java.io.*;
 
/**
 * Created by yjl on 2021/4/30.
 * 動(dòng)物類(lèi)
 * 原型模式:博文介紹鏈接:https://blog.csdn.net/qq_27471405/article/details/116309878
 */
public abstract class Animal implements Cloneable, Serializable{
    private String id;
    public String name;
 
    abstract void shout();
 
    public String getId() {
        return id;
    }
 
    public void setId(String id) {
        this.id = id;
    }
 
 
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
    /**
     * 淺復(fù)制
     */
    public Object clone() throws CloneNotSupportedException {
        Animal clone = (Animal) super.clone();
        return clone;
    }
 
 
    /**
     * 深復(fù)制
     */
    public Object deepClone() {
        ByteArrayOutputStream byteArrayOutputStream = null;
        ObjectOutputStream objectOutputStream = null;
        ByteArrayInputStream byteArrayInputStream = null;
        ObjectInputStream objectInputStream = null;
        try {
            // 序列化
            byteArrayOutputStream = new ByteArrayOutputStream();
            objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
            objectOutputStream.writeObject(this);/*將當(dāng)前對(duì)象以對(duì)象流的方式輸出*/
            //反序列化
            byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
            objectInputStream = new ObjectInputStream(byteArrayInputStream);
            Animal deepProtoType = (Animal) objectInputStream.readObject();
            return deepProtoType;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        } finally {
            try {
                byteArrayOutputStream.close();
                objectOutputStream.close();
                byteArrayInputStream.close();
                objectInputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
 
        }
 
    }
}

測(cè)試一下結(jié)果

package cn.zygxsq.design.module.prototypePattern;
 
import com.alibaba.fastjson.JSON;
 
/**
 * Created by yjl on 2021/4/30.
 * 測(cè)試主類(lèi) 深復(fù)制
 * 原型模式:博文介紹鏈接:https://blog.csdn.net/qq_27471405/article/details/116309878
 */
public class TestPrototypeDeepClone {
    public static void main(String[] args) {
        DataCache.init(); // 模擬加載數(shù)據(jù)到緩存中
 
        try {
            Animal a1 = DataCache.getAnimal("111");
            Animal a2 = (Animal)a1.deepClone();
            System.out.println(a1==a2);
            System.out.println(a1.name == a2.name);
            System.out.println(a1.name);
        } catch (Exception e) {
            e.printStackTrace();
        }
 
 
    }
}

 運(yùn)行結(jié)果:

這就是深復(fù)制和淺復(fù)制以及原型模式的使用

到此這篇關(guān)于Java設(shè)計(jì)模式之原型模式詳解的文章就介紹到這了,更多相關(guān)Java原型模式內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Spring?Integration概述與怎么使用詳解

    Spring?Integration概述與怎么使用詳解

    公司項(xiàng)目需要用到spring integration,而網(wǎng)上關(guān)于spring integration的有價(jià)值的參考資料比較少,下面這篇文章主要給大家介紹了關(guān)于Spring?Integration概述與怎么使用的相關(guān)資料,需要的朋友可以參考下
    2023-02-02
  • java中處理stream.filter()的實(shí)例代碼

    java中處理stream.filter()的實(shí)例代碼

    stream()是Java 8中的一個(gè)函數(shù)式接口,用于處理數(shù)據(jù)流,它可以從一個(gè)數(shù)據(jù)源,如集合,數(shù)組等生成一個(gè)流,這篇文章主要給大家介紹了關(guān)于java中處理stream.filter()的相關(guān)資料,需要的朋友可以參考下
    2024-08-08
  • SpringBoot整合RabbitMQ的5種模式的注解綁定詳解

    SpringBoot整合RabbitMQ的5種模式的注解綁定詳解

    這篇文章主要介紹了SpringBoot整合RabbitMQ的5種模式的注解綁定詳解,RabbitMQ 是一個(gè)消息中間件,它接收消息并且轉(zhuǎn)發(fā),是"消費(fèi)-生產(chǎn)者模型"的一個(gè)典型的代表,一端往消息隊(duì)列中不斷的寫(xiě)入消息,而另一端則可以讀取或者訂閱隊(duì)列中的消息,需要的朋友可以參考下
    2024-01-01
  • Java關(guān)于重排鏈表詳細(xì)解析

    Java關(guān)于重排鏈表詳細(xì)解析

    在我們平時(shí)的代碼過(guò)程中,鏈表是我們經(jīng)常遇到的一個(gè)數(shù)據(jù)結(jié)構(gòu),面試題中鏈表占很大一部分,可見(jiàn)鏈表操作是非常重要的。本篇文章我們來(lái)探究一下如何進(jìn)行重排鏈表
    2022-01-01
  • Spring Boot 自定義 Shiro 過(guò)濾器無(wú)法使用 @Autowired問(wèn)題及解決方法

    Spring Boot 自定義 Shiro 過(guò)濾器無(wú)法使用 @Autowired問(wèn)題及解決方法

    這篇文章主要介紹了Spring Boot 自定義 Shiro 過(guò)濾器無(wú)法使用 @Autowired問(wèn)題及解決方法 ,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2019-06-06
  • 淺談SpringCloud的微服務(wù)架構(gòu)組件

    淺談SpringCloud的微服務(wù)架構(gòu)組件

    這篇文章主要介紹了淺談SpringCloud的微服務(wù)架構(gòu)組件,Spring Cloud根據(jù)分布式服務(wù)協(xié)調(diào)治理的需求成立了許多子項(xiàng)目,每個(gè)項(xiàng)目通過(guò)特定的組件去實(shí)現(xiàn),需要的朋友可以參考下
    2023-04-04
  • shiro與spring?security用自定義異常處理401錯(cuò)誤

    shiro與spring?security用自定義異常處理401錯(cuò)誤

    這篇文章主要介紹了shiro與spring?security用自定義異常處理401錯(cuò)誤,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • 使用Feign調(diào)用時(shí)添加驗(yàn)證信息token到請(qǐng)求頭方式

    使用Feign調(diào)用時(shí)添加驗(yàn)證信息token到請(qǐng)求頭方式

    這篇文章主要介紹了使用Feign調(diào)用時(shí)添加驗(yàn)證信息token到請(qǐng)求頭方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-03-03
  • SpringBoot 微信退款功能的示例代碼

    SpringBoot 微信退款功能的示例代碼

    這篇文章主要介紹了SpringBoot 微信退款功能的實(shí)現(xiàn),本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-06-06
  • SpringBoot 注解事務(wù)聲明式事務(wù)的方式

    SpringBoot 注解事務(wù)聲明式事務(wù)的方式

    springboot使用上述注解的幾種方式開(kāi)啟事物,可以達(dá)到和xml中聲明的同樣效果,但是卻告別了xml,使你的代碼遠(yuǎn)離配置文件。今天就扒一扒springboot中事務(wù)使用注解的玩法,感興趣的朋友一起看看吧
    2017-09-09

最新評(píng)論

南木林县| 南和县| 大悟县| 通化县| 洛川县| 南通市| 武宁县| 德庆县| 招远市| 闽侯县| 余干县| 姜堰市| 大同市| 台湾省| 博白县| 衢州市| 黄山市| 收藏| 亚东县| 开远市| 雅安市| 东阳市| 翼城县| 武胜县| 长丰县| 平凉市| 垫江县| 军事| 华阴市| 四平市| 高州市| 航空| 余干县| 措美县| 大城县| 信宜市| 青海省| 鹤峰县| 林周县| 高清| 陵川县|