答えは、プロトタイプ パターンを使用することです。
プロトタイプ モードの利点は、元のインスタンスに影響を与えることなく使用するインスタンスのプロパティをコピーするのに便利なことです. そのロジックは、Cloneable
インターフェイス.
早速、 の主要なソース コードIntent
を。
// frameworks/base/core/java/android/content/Intent.java
public class Intent implements Parcelable, Cloneable {
...
private static final int COPY_MODE_ALL = 0;
private static final int COPY_MODE_FILTER = 1;
private static final int COPY_MODE_HISTORY = 2;
@Override
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.mIdentifier = o.mIdentifier;
this.mPackage = o.mPackage;
this.mComponent = o.mComponent;
this.mOriginalIntent = o.mOriginalIntent;
...
if (copyMode != COPY_MODE_FILTER) {
...
if (copyMode != COPY_MODE_HISTORY) {
...
}
}
}
...
}
复制代码
実装されたロジックは、コピーのために super.clone() を呼び出すのではなく、直接 new を呼び出して独自のインスタンスを渡すことであることがIntent
わかります。clone()
デフォルトのコピー戦略はCOPY_MODE_ALL
、名前が示すように、ソース インスタンスのすべての属性の完全なコピーで構築することです。他のコピー戦略はCOPY_MODE_FILTER
、Intent-filterに関連する属性、つまり、開始ターゲット コンポーネントを決定するために使用されるaction、data、type、component、categoryなどの必要な情報のみをコピーすることを指します。開始フラグ、バンドル、およびその他のデータを無視します。
// frameworks/base/core/java/android/content/Intent.java
public class Intent implements Parcelable, Cloneable {
...
public @NonNull Intent cloneFilter() {
return new Intent(this, COPY_MODE_FILTER);
}
private Intent(Intent o, @CopyMode int copyMode) {
this.mAction = o.mAction;
...
if (copyMode != COPY_MODE_FILTER) {
this.mFlags = o.mFlags;
this.mContentUserHint = o.mContentUserHint;
this.mLaunchToken = o.mLaunchToken;
...
}
}
}
复制代码
さらに、コピー戦略では、バンドルなどの履歴データはCOPY_MODE_HISTORY
必要ありませんが、アクションなどの基本的な情報や起動フラグなどのデータは保持されます。
// frameworks/base/core/java/android/content/Intent.java
public class Intent implements Parcelable, Cloneable {
...
public Intent maybeStripForHistory() {
if (!canStripForHistory()) {
return this;
}
return new Intent(this, COPY_MODE_HISTORY);
}
private Intent(Intent o, @CopyMode int copyMode) {
this.mAction = o.mAction;
...
if (copyMode != COPY_MODE_FILTER) {
...
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.isDefinitelyEmpty()) {
this.mExtras = Bundle.STRIPPED;
}
}
}
}
}
复制代码
要約すると:
コピーモード | アクションおよびその他のデータ | フラグとその他のデータ | バンドルとその他の履歴 |
---|---|---|---|
COPY_MODE_ALL | はい | はい | はい |
COPY_MODE_FILTER | はい | いいえ | いいえ |
COPY_MODE_HISTORY | YES | YES | NO |
除了 Intent
,Android 源码中还有很多地方采用了原型模式。
-
Bundle
也实现了 clone(),提供了 new Bundle(this) 的处理:public final class Bundle extends BaseBundle implements Cloneable, Parcelable { ... @Override public Object clone() { return new Bundle(this); } } 复制代码
-
组件信息类
ComponentName
也在 clone() 中提供了类似的实现:public final class ComponentName implements Parcelable, Cloneable, Comparable<ComponentName> { ... public ComponentName clone() { return new ComponentName(mPackage, mClass); } } 复制代码
-
工具类
IntArray
亦是如此:public class IntArray implements Cloneable { ... @Override public IntArray clone() { return new IntArray(mValues.clone(), mSize); } } 复制代码
原型模式也不一定非得实现 Cloneable,提供了类似的实现即可。比如:
-
Bitmap
没有实现该接口但提供了copy()
,内部将传递原始 Bitmap 在 native 中的对象指针并伴随目标配置进行新实例的创建:public final class ComponentName implements Parcelable, Cloneable, Comparable<ComponentName> { ... public Bitmap copy(Config config, boolean isMutable) { ... noteHardwareBitmapSlowCall(); Bitmap b = nativeCopy(mNativePtr, config.nativeInt, isMutable); if (b != null) { b.setPremultiplied(mRequestPremultiplied); b.mDensity = mDensity; } return b; } } 复制代码