1. 程式人生 > >【設計模式與Android】原型模式——復制中心走出來的克隆人

【設計模式與Android】原型模式——復制中心走出來的克隆人

設計模式 android

什麽是原型模式

所謂原型模式,就是用原型實例來指定創建對象的種類,並通過復制這些原型創建新的對象的設計模式。原型模式一般用於創建復雜的或者構建耗時的實例,或者用於只讀對象的修改。

原型模式的實現方式

(1)淺拷貝

當代的每個程序員小時候都玩過《尤裏的復仇》這款遊戲,遊戲中的“尤裏”陣營有個兵種叫“尤裏復制人”,每個尤裏復制人都和尤裏長得一模一樣,除了沒有坐騎之外。

public class Yuri{

private String name = "Yuri";

private ArrayList<String> words = new ArrayList<>();



public void setName(String name) {
this.name = name;
}

public void addWord(String word){
this.words.add(word);
}

@Override
protected Yuri clone(){
try{
return (Yuri) super.clone();
}catch (CloneNotSupportedException e){
return null
;
}
}

@Override
public String toString() {
return "Yuri{" +
"name=‘" + name + \‘+
", words=" + words.toString() +
‘}‘;
}
}

如上,重寫了clone()方法。在執行如下代碼時:

Yuri yuri = new Yuri();
yuri.setName("Yuri");
yuri.addWord("My name is Yuri");
yuri.addWord

("You mind is clear");

Yuri yuri_copyer = yuri.clone();
yuri.setName("Yuri‘s copyer");

yuri.addWord("I‘m not the only one true Yuri");



Log.e("yuri_copyer",yuri_copyer.toString());
Log.e("yuri",yuri.toString());

會驚奇地發現兩行Log一模一樣,這是因為這種原型模式的實現方式只拷貝其引用,換句話說就是並沒有將原型對象中的所有字段都重新構造一份,只是用復制對象的字段引用原型對象中的字段,因此被稱為“淺拷貝”或“影子拷貝”。

(2)深拷貝

我們把上文的clone()方法修改一下:

@Override
protected Yuri clone(){
try{
Yuri copyer = (Yuri) super.clone();
copyer.name = this.name;
copyer.words = (ArrayList<String>)this.words.clone();
return copyer;
}catch (CloneNotSupportedException e){
return null;
}
}

如上,這種實現方式調用了的clone()方法,這樣可以保證副本被修改時不影響原始對象,因此被稱為“深拷貝”,又叫做“保護性拷貝”。

Android源碼中的原型模式

1)ArrayList

嚴格來說ArrayList並不算是Android源碼中的類,但應該是Android開發者最常用的類,ArrayList的clone()代碼如下:

/**
* Returns a shallow copy of this <tt>ArrayList</tt> instance. (The
* elements themselves are not copied.)
*
* @return a clone of this <tt>ArrayList</tt> instance
*/
public Object clone() {
try {
ArrayList<?> v = (ArrayList<?>) super.clone();
v.elementData = Arrays.copyOf(elementData, size);
v.modCount = 0;
return v;
} catch (CloneNotSupportedException e) {
// this shouldn‘t happen, since we are Cloneable
throw new InternalError(e);
}
}

大家可以看到size並沒有被clone,因為size是基礎類型而不是引用類型,所以不需要clone。細心的讀者可以看到註釋裏面的“shallow copy”,但這實際上是一個典型的深拷貝。

(3)Intent

Android系統加入Intent機制的意義在於大大降低了Android四大組件之間的耦合度。Intent的clone()代碼如下:

@Override
public Object clone() {
return new Intent(this);
}

/**
* Copy constructor.
*/
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的clone()內部並沒有調用super.clone(),而是調用了new Intent(this)。

Android開發中如何利用原型模式

(1)Object的clone()方法直接操作二進制流,效率非常高。在對象的初始化要消耗非常多的資源時,或者用new來實例化一個對象時需要非常繁瑣的數據準備或訪問權限時,可以使用原型模式提高效率、避免消耗資源。

2)對深拷貝生成的副本進行修改不會影響原始對象。當一個對象會被不同對象用不同方式修改時,可以用原型模式產生副本供調用者使用。

需要註意的幾個問題

(1)原型模式在clone()的時候不會重新執行構造函數,可能會出現問題。

(2)在某些對象構造非常簡單的情況下,比如上文提到的Intent,重新new一個比clone()快,因此不要濫用原型模式


本文出自 “玖哥的書房” 博客,請務必保留此出處http://dongfeng9ge.blog.51cto.com/9191243/1972482

【設計模式與Android】原型模式——復制中心走出來的克隆人