設(shè)計(jì)模式之原型模式 PrototypePattern

一、模式定義

通過(guò)復(fù)制現(xiàn)有實(shí)例來(lái)創(chuàng)建新的實(shí)例,無(wú)需知道相應(yīng)類(lèi)的信息。

二、模式使用場(chǎng)景

  • 類(lèi)初始化需要消耗非常多的資源。
  • 通過(guò)new產(chǎn)生一個(gè)對(duì)象需要非常繁瑣的數(shù)據(jù)準(zhǔn)備或訪問(wèn)權(quán)限。
  • 提供給其他對(duì)象訪問(wèn),而且各個(gè)調(diào)用者可能需要修改其值時(shí)。

三、代碼實(shí)現(xiàn)

public class WordDocument implements Cloneable {
    private String mText;
    private ArrayList<String> mImages = new ArrayList<>();
    public WordDocument() {
    }
    @Override
    public WordDocument clone() {
        try {
            WordDocument doc = (WordDocument) super.clone();
            // 淺拷貝,只是單純的只想了內(nèi)存引用
            doc.mText = this.mText;
            doc.mImages = this.mImages;
            // 深拷貝,操作副本時(shí)不會(huì)影響原始對(duì)象
            doc.mImages = (ArrayList<String>) this.mImages.clone();
            return doc;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    //省略構(gòu)造函數(shù)...
}

四、深拷貝和淺拷貝的區(qū)別

  • 深拷貝:拷貝時(shí)創(chuàng)建一個(gè)新的對(duì)象,并且所有屬性都是新對(duì)象(指向新的內(nèi)存地址)。對(duì)復(fù)制后的對(duì)象進(jìn)行修改,不會(huì)影響原來(lái)對(duì)象的值。
  • 淺拷貝:拷貝時(shí)創(chuàng)建一個(gè)新的對(duì)象,對(duì)象中的屬性如果是基本數(shù)據(jù)類(lèi)型會(huì)新創(chuàng)建的對(duì)象,但是屬性是引用類(lèi)型不會(huì)創(chuàng)建新的對(duì)象,而是使用與之前的對(duì)象指向同一個(gè)內(nèi)存地址。對(duì)復(fù)制后的對(duì)象進(jìn)行修改,仍然會(huì)影響原來(lái)對(duì)象的值。

五、Android源碼分析

Android中的Intent就實(shí)現(xiàn)了Cloneable接口,但是clone()方法中卻是通過(guò)new來(lái)創(chuàng)建對(duì)象的。

public class Intent implements Parcelable, Cloneable {
        //其他代碼略
        @Override
        public Object clone() {
            //這里沒(méi)有調(diào)用super.clone()來(lái)實(shí)現(xiàn)拷貝,而是直接通過(guò)new來(lái)創(chuàng)建
            return new Intent(this);
        }
        public Intent(Intent o) {
            this.mAction = o.mAction;
            this.mData = o.mData;
            this.mType = o.mType;
            this.mPackage = o.mPackage;
            this.mComponent = o.mComponent;
            this.mFlags = o.mFlags;
            this.mContentUserHint = o.mContentUserHint;
            if (o.mCategories != null) {
                this.mCategories = new ArraySet<String>(o.mCategories);
            }
            if (o.mExtras != null) {
                this.mExtras = new Bundle(o.mExtras);
            }
            if (o.mSourceBounds != null) {
                this.mSourceBounds = new Rect(o.mSourceBounds);
            }
            if (o.mSelector != null) {
                this.mSelector = new Intent(o.mSelector);
            }
            if (o.mClipData != null) {
                this.mClipData = new ClipData(o.mClipData);
            }
        }
    }

在《 Android 源碼設(shè)計(jì)模式解析與實(shí)戰(zhàn)》中講到,在 Intent 的 clone 方法中并沒(méi)有調(diào)用 super.clone() 方法來(lái)實(shí)現(xiàn)對(duì)象拷貝,而是調(diào)用 new Intent() 的原因是:使用 clone 和 new 需要根據(jù)構(gòu)造對(duì)象的成本來(lái)決定,如果對(duì)象的構(gòu)造成本或者構(gòu)造較為麻煩的時(shí)候使用 clone 函數(shù)效率較高,否則可以使用 new 的形式。

六、模式優(yōu)缺點(diǎn)

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

    1. 原型模式是在內(nèi)存中二進(jìn)制流的拷貝,要比直接new一個(gè)對(duì)象性能好,特別是產(chǎn)生大量對(duì)象時(shí)。
    2. 隱藏制造新實(shí)例的重要性。
    3. 在重復(fù)創(chuàng)建相似對(duì)象的時(shí)候可以用。
  • 缺點(diǎn)

    1. 直接在內(nèi)存中拷貝,構(gòu)造函數(shù)是不會(huì)執(zhí)行的,應(yīng)該注意這個(gè)潛在問(wèn)題。
    2. 每個(gè)類(lèi)都必須配備一個(gè)克隆方法。
    3. 深拷貝會(huì)較為復(fù)雜。

七、總結(jié)

原型模式本質(zhì)上就是對(duì)象拷貝,使用原型模式可以解決構(gòu)造復(fù)雜對(duì)象的資源消耗問(wèn)題,能夠在某些場(chǎng)景下提升創(chuàng)建對(duì)象的效率。還有一個(gè)重要用途就是保護(hù)性拷貝,也就是某個(gè)對(duì)象對(duì)外可能是只讀的,為了防止外部對(duì)這個(gè)只讀對(duì)象進(jìn)行修改,通常可以通過(guò)返回一個(gè)對(duì)象拷貝的形式實(shí)現(xiàn)只讀的限制。另外需要區(qū)別淺拷貝和深拷貝,它們之間容易出現(xiàn)問(wèn)題,

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容