1. 程式人生 > 實用技巧 >java執行緒-看這一篇就夠了

java執行緒-看這一篇就夠了

原型模式

一、簡介

該模式多用於建立複雜的或者構造耗時的例項。

定義:用原型例項指定建立物件的種類,並通過拷貝這些原型建立新的物件。

二、原型模式的使用場景

  • 如果類的初始化需要耗費較多的資源,那麼可以通過原型拷貝避免這些消耗。
  • 通過new產生一個物件需要非常繁瑣的資料準備或訪問許可權,則可以使用原型模式。
  • 一個物件需要提供給其他物件訪問,而且各個呼叫者可能都需要修改其值時,可以拷貝多個物件供呼叫者使用,即保護性拷貝。

三、原型模式模式簡單實現

    public static class WordDocument implements Cloneable{
        private String text;
        private ArrayList<String> images=new ArrayList<>();

        public WordDocument() {
        }

        public String getText() {
            return text == null ? "" : text;
        }

        public void setText(String text) {
            this.text = text;
        }

        public ArrayList<String> getImages() {
            if (images == null) {
                return new ArrayList<>();
            }
            return images;
        }

        public void setImages(String images) {
            this.images.add(images);
        }

        @Override
        protected Object clone() throws CloneNotSupportedException {
            try {
                WordDocument document= (WordDocument) super.clone();
                document.text=this.text;
                //淺拷貝
                document.images=this.images;
                //深拷貝
//                document.images= (ArrayList<String>) this.images.clone();
                return document;
            }catch (Exception e){

            }
            return null;
        }

        @Override
        public String toString() {
            return "WordDocument{" +
                    "text='" + text + '\'' +
                    ", images=" + images +
                    '}';
        }
    }

    public static void cloneWordDocument() throws CloneNotSupportedException {
        WordDocument origindoc=new WordDocument();
        origindoc.setText("the first doc");
        origindoc.setImages("image1");
        origindoc.setImages("image2");
        Log.i(TAG, "cloneWordDocument: origin "+origindoc.toString());

        WordDocument clonedoc= (WordDocument) origindoc.clone();
        clonedoc.setText("the second doc");
        Log.i(TAG, "cloneWordDocument: clone "+clonedoc.toString());
        Log.i(TAG, "cloneWordDocument: origin "+origindoc.toString());
    }

上述log如下所示:

可以看出clone的物件改變text值並不會影響origin。但是如果我們為clone新增一個images這時origin也會受到影響,這是因為上面對images的拷貝是基於淺拷貝的。

克隆出來的新物件的images沒有重新構造出新的images而是引用origin的images,所以兩者的images實際是指向同一物件的,要解決這個問題我們需要使用深拷貝,即對引用型別的欄位也要呼叫其clone方法進行克隆。

四、Android中原型模式的使用

Intent是我們經常使用的一個類,它提供了clone方法,我們一起來看下

   public Object clone() {
        return new Intent(this);
    }
    
     public Intent(Intent o) {
        this(o, COPY_MODE_ALL);
    }

    private Intent(Intent o, @CopyMode int copyMode) {
        this.mAction = o.mAction;
        this.mData = o.mData;
        this.mType = o.mType;
        this.mPackage = o.mPackage;
        this.mComponent = o.mComponent;

        if (o.mCategories != null) {
            this.mCategories = new ArraySet<>(o.mCategories);
        }

        if (copyMode != COPY_MODE_FILTER) {
            this.mFlags = o.mFlags;
            this.mContentUserHint = o.mContentUserHint;
            this.mLaunchToken = o.mLaunchToken;
            if (o.mSourceBounds != null) {
                this.mSourceBounds = new Rect(o.mSourceBounds);
            }
            if (o.mSelector != null) {
                this.mSelector = new Intent(o.mSelector);
            }

            if (copyMode != COPY_MODE_HISTORY) {
                if (o.mExtras != null) {
                    this.mExtras = new Bundle(o.mExtras);
                }
                if (o.mClipData != null) {
                    this.mClipData = new ClipData(o.mClipData);
                }
            } else {
                if (o.mExtras != null && !o.mExtras.maybeIsEmpty()) {
                    this.mExtras = Bundle.STRIPPED;
                }

                // Also set "stripped" clip data when we ever log mClipData in the (broadcast)
                // history.
            }
        }
    }

可以看出Intent內部的clone方法並沒有呼叫super.clone來拷貝物件,而是new了一個新的例項。其實使用clone還是new需要根據實際情況來決定,如果構造新的例項的成本比較高那麼就可以使用clone,否則可以使用new。