原型模式
原型模式
一、简介
该模式多用于创建复杂的或者构造耗时的实例。
定义:用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象。
二、原型模式的使用场景
- 如果类的初始化需要耗费较多的资源,那么可以通过原型拷贝避免这些消耗。
- 通过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。