一、模式定义
通过复制现有实例来创建新的实例,无需知道相应类的信息。
二、模式使用场景
- 类初始化需要
消耗
非常多的资源。 - 通过new产生一个对象需要非常
繁琐
的数据准备或访问权限。 - 提供给其他对象访问,而且各个调用者可能需要
修改
其值时。
三、代码实现
public class WordDocument implements Cloneable {
private String mText;
private ArrayList<String> mImages = new ArrayList<>();
public WordDocument() {
}
@Override
public WordDocument clone() {
try {
WordDocument doc = (WordDocument) super.clone();
// 浅拷贝,只是单纯的只想了内存引用
doc.mText = this.mText;
doc.mImages = this.mImages;
// 深拷贝,操作副本时不会影响原始对象
doc.mImages = (ArrayList<String>) this.mImages.clone();
return doc;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
//省略构造函数...
}
四、深拷贝和浅拷贝的区别
-
深拷贝:拷贝时创建一个
新的对象
,并且所有属性都是新对象(指向新的内存地址)。对复制后的对象进行修改,不会影响
原来对象的值。 -
浅拷贝:拷贝时创建一个新的对象,对象中的属性如果是
基本数据类型
会新创建的对象,但是属性是引用类型
不会创建新的对象,而是使用与之前的对象指向同一个内存地址
。对复制后的对象进行修改,仍然会影响
原来对象的值。
五、Android源码分析
Android中的Intent就实现了Cloneable接口,但是clone()方法中却是通过new来创建对象
的。
public class Intent implements Parcelable, Cloneable {
//其他代码略
@Override
public Object clone() {
//这里没有调用super.clone()来实现拷贝,而是直接通过new来创建
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);
}
}
}
在《 Android 源码设计模式解析与实战》中讲到,在 Intent 的 clone 方法中并没有调用 super.clone() 方法来实现对象拷贝,而是调用 new Intent() 的原因是:使用 clone 和 new 需要根据构造对象的成本来决定,如果对象的
构造成本
或者构造较为麻烦
的时候使用 clone 函数效率较高,否则可以使用 new 的形式。
六、模式优缺点
-
优点
- 原型模式是在内存中二进制流的拷贝,要比直接new一个对象性能好,特别是产生大量对象时。
- 隐藏制造新实例的重要性。
- 在重复创建相似对象的时候可以用。
-
缺点
- 直接在内存中拷贝,
构造函数是不会执行的
,应该注意这个潜在问题。 - 每个类都必须配备一个克隆方法。
- 深拷贝会较为复杂。
- 直接在内存中拷贝,
七、总结
原型模式本质上就是对象拷贝,使用原型模式可以解决构造复杂对象的资源消耗问题,能够在某些场景下提升创建对象的效率。还有一个重要用途就是保护性拷贝
,也就是某个对象对外可能是只读
的,为了防止外部对这个只读对象进行修改,通常可以通过返回一个对象拷贝的形式实现只读的限制。另外需要区别浅拷贝和深拷贝
,它们之间容易出现问题,
网友评论