java執行緒-看這一篇就夠了
阿新 • • 發佈:2020-10-09
原型模式
一、簡介
該模式多用於建立複雜的或者構造耗時的例項。
定義:用原型例項指定建立物件的種類,並通過拷貝這些原型建立新的物件。
二、原型模式的使用場景
- 如果類的初始化需要耗費較多的資源,那麼可以通過原型拷貝避免這些消耗。
- 通過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。