La respuesta es usar el patrón prototipo .
La ventaja del modo prototipo es que es conveniente copiar las propiedades de una instancia para su uso sin afectar la instancia original, su lógica radica en la implementación de Cloneable
la interfaz .
Sin más preámbulos, veamos el código fuente clave Intent
de :
// 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) {
...
}
}
}
...
}
复制代码
Se puede ver Intent
que clone()
la lógica implementada es llamar directamente a new y pasar su propia instancia en lugar de llamar a super.clone() para copiar.
La estrategia de copia predeterminada es COPY_MODE_ALL
, como su nombre lo indica, construir con una copia completa de todos los atributos de la instancia de origen. Otras estrategias de copia COPY_MODE_FILTER
se refieren a copiar solo los atributos relacionados con el Intent-filter , es decir, la información necesaria como acción , datos , tipo , componente , categoría , etc. utilizada para determinar el componente de destino inicial. Ignore la bandera de inicio , el paquete y otros datos.
// 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;
...
}
}
}
复制代码
Además COPY_MODE_HISTORY
, la estrategia de copia no requiere datos históricos como paquetes , sino que conserva información básica como acciones y datos como indicadores de inicio .
// 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;
}
}
}
}
}
复制代码
En resumen:
Modo de copia | Acción y otros datos | banderas y otros datos | Paquete y otra historia |
---|---|---|---|
COPY_MODE_ALL | SÍ | SÍ | SÍ |
COPY_MODE_FILTER | SÍ | NO | NO |
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; } } 复制代码