定義
原型的是一種創(chuàng)建型的設(shè)計模式超棺,主用來創(chuàng)建的復(fù)雜的對象和構(gòu)建耗時的實例。通過克隆已有的對象來創(chuàng)建的新的對象,從而節(jié)省時間和內(nèi)存。通過克隆一個已經(jīng)存在的實例可以使我們的程序運(yùn)行的更高效笆呆。
使用場景
(1)類初始化需要消化非常多的資源,這個資源包括數(shù)據(jù)粱挡、硬件資源等赠幕,通過原型拷貝避免這些消耗。
(2)通過new產(chǎn)生的一個對象需要非常繁瑣的數(shù)據(jù)準(zhǔn)備或者權(quán)限询筏,這時可以使用原型模式榕堰。
(3)一個對象需要提供給其他對象訪問,而且各個調(diào)用者可能都需要修改其值時,可以考慮使用原型模式拷貝多個對象供調(diào)用者使用逆屡,即保護(hù)性拷貝圾旨。
如何實現(xiàn)
首先我們得實現(xiàn)Cloneable接口,復(fù)寫clone方法
implements Cloneable
@Override
protected User clone() {
User user = null;
try{
user = (User)super.clone();
} catch (CloneNotSupportedException e){
e.printStackTrace();
}
return user;
}
我們需要注意魏蔗,clone這個方法不是Cloneable接口中的砍的,我們來看Cloneable的定義,是一個空的接口莺治。
* @author unascribed
* @see java.lang.CloneNotSupportedException
* @see java.lang.Object#clone()
* @since JDK1.0
*/
public interface Cloneable {
}
那么clone是哪來的呢廓鞠,其實clone是Object中的方法,Cloneable是一個標(biāo)識接口谣旁,它表明這個類的對象是可以拷貝的床佳。如果沒有實現(xiàn)Cloneable接口卻調(diào)用了clone()函數(shù)將拋出異常。
淺拷貝和深拷貝
那么在實現(xiàn)clone方法的時候榄审,需要注意個問題砌们,像上面那樣,直接調(diào)用
user = (User)super.clone();
這樣只是簡單的拷貝了對象搁进,實際上并不是將原始文檔的所有字段都重新構(gòu)造了一份浪感,而是副本文檔的字段引用原始文檔的字段。我們需要自己賦值其成員變量拷获,尤其當(dāng)成員變量為引用型對象時篮撑,邊涉及到了淺拷貝和深拷貝的問題。
那么什么是深拷貝呢匆瓜,如何做赢笨? 其實就是拷貝時,我們的引用對象也得拷貝驮吱,更有甚者茧妒,比如Android中的Intent的深拷貝直接是new一個。
那我們來看一下深拷貝的demo代碼:
@Override
public WordDocument clone() {
try {
WordDocument doc = (WordDocument) super.clone();
doc.mText = this.mText;
doc.mImages = (ArrayList<String>) this.mImages.clone();
return doc;
} catch (CloneNotSupportedException e) {
}
return null;
}
應(yīng)用
那么原型模式左冬,在我們的Android中有什么經(jīng)典應(yīng)用呢桐筏。此時我打開了AndroidStudio,直接跳到了我們的Intenet源碼拇砰。
*
* <p>These are the possible flags that can be used in the Intent via
* {@link #setFlags} and {@link #addFlags}. See {@link #setFlags} for a list
* of all possible flags.
*/
public class Intent implements Parcelable, Cloneable {
...
@Override
public Object clone() {
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);
}
}
...
}
可以見到梅忌,我們的Intent是深度拷貝,而且是直接new一個的深度拷貝除破∧恋可見其設(shè)計初衷不是因為其不是為了解決構(gòu)建復(fù)雜對象的資源消耗問題。
總結(jié)
原型模式本質(zhì)上就是對象拷貝瑰枫,與 C++ 中的拷貝構(gòu)造函數(shù)有些類似踱葛,它們之間容易出現(xiàn)的問題也都是深拷貝、淺拷貝。使用原型模式可以解決構(gòu)建復(fù)雜對象的資源消耗問題尸诽,能夠在某些場景下提升創(chuàng)建對象的效率甥材。還有一個重要的途徑就是保護(hù)性拷貝,也就是某個對象對外可能是只讀的性含,為了防止外部對這個只讀對象修改洲赵,通常可以通過返回一個對象拷貝的形式實現(xiàn)只讀的限制胶滋。
優(yōu)點:原型模式是在內(nèi)存中二進(jìn)制流的拷貝板鬓,要比直接 new 一個對象性能好很多悲敷,特別是要在一個循環(huán)體內(nèi)產(chǎn)生大量的對象時究恤,原型模式可以更好滴體現(xiàn)其優(yōu)點。
缺點:這既是它的優(yōu)點也是缺點后德,直接在內(nèi)存中拷貝部宿,構(gòu)造函數(shù)是不會執(zhí)行的,在實際開發(fā)中應(yīng)該注意這個潛在問題瓢湃,優(yōu)點就是減少了約束理张,缺點也是減少了約束,需要大家在實際應(yīng)用是考慮绵患。
謝謝大家閱讀雾叭,如有幫助,來個喜歡或者關(guān)注吧落蝙!
本文作者:Anderson/Jerey_Jobs
簡書地址:[Anderson大碼渣][1]
github地址:[Jerey_Jobs][2]
[1]: http://www.reibang.com/users/016a5ba708a0/latest_articles
[2]: https://github.com/Jerey-Jobs