原型模式是一种创建型模式,允许用户从一个样板实例中复制出一个内部属性一致的对象,俗称为克隆
.被复制出来的实例就是我们所称的原型.
多用在创建实例比较复杂或者耗时的情况下,因为复制一个已经存在的实例可以使程序运行更高效.
用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象。
new
产生一个对象需要非常繁琐的数据准备或访问权限clone
能力。原型模式主要用于对象的复制,其原型类(ConcretePrototype
)想要被复制,需要满足如下条件
实现Cloneable
接口,此接口相当于Prototype
角色.
复写 clone
方法.并将其包访问权限修改为public
的.
Object中的
clone
方法是受保护的,如果一个类实现了Cloneable
接口,clone
方法就会返回改对象的逐域拷贝,否则会抛出CloneNotSupportedException
异常
Cloneable
接口中没有任何方法,它仅仅是一个标记接口,只有实现此接口的对象才能被拷贝。
在Java中,如果我们将原始对象的值赋给另一个对象,就是值的传递,如
int a = 1;
int b = a;
如果将引用类型的值赋给另一个对象,则是引用的传递,如
String[] a = new String[5];
String[] b = a;//这里b只是指向了a的引用
如果我们只是实现了Cloneable
接口,并简单的使用super.clone()
来复写clone
方法的话,那么基本上就是浅拷贝,浅拷贝对于引用类型就如上一样,并不是真正的拷贝.
public class Clone implements Cloneable{
private int mInt;
private ArrayList mList;
@Override protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
//....
}
CloneImpl cloneImpl = new CloneImpl();
//...
try {
Object clone = cloneImpl.clone();
CloneImpl cloneImpl1 = (CloneImpl) clone;
//...
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
通过日志打印,可以看到源mList
的值会因为clone
实例的改变而改变.而mInt
值不变.
浅拷贝的特点:
浅拷贝适用于 对象只包含原始数据域或者不可变对象域的时候,提高效率
深拷贝可以做到保护性拷贝,看ArrayList
的源码,我们发现其实现了Cloneable
接口,并重写了clone()
方法.因此,将上述代码修改为如下形式
@Override protected Object clone() throws CloneNotSupportedException {
CloneImpl2 clone = (CloneImpl2) super.clone();
clone.mList = (ArrayList) mList.clone();
return clone;
}
之后再次执行clone()
后,这是clone
实例的改变就不会影响到源对象了
深拷贝的特点:
clone
方法的时候,需要调用属性的clone
方法100%
保护性拷贝当对象存在引用类型的属性,要使用深拷贝.为了防止错误的发生,在使用对象拷贝的时候,建议尽量使用深拷贝
Effective Java
第11条,要谨慎的覆盖clone
中有这样的描述,对于任何对象x,表达式
x.clone() != x 将会是 true
x.clone().getClass() == x.getClass() 将会是 true,但不是绝对要求 x.clone().equals(x) 将会是 true,但也不是绝对的要求
拷贝对象会创建一个类新的实例,并会拷贝其内部结构,但是不会调用构造器
private
的.原型
与 clone
实例通过 equals
和 ==
比较返回值都是 false
clone()
方法是直接new
一个对象,如Intent
,需要根据创建对象的复杂程度来决定.final
关键字的拷贝无法编译通过Object
中的clone()
方法是线程不同步的.在需要线程安全的场景,需要做好同步工作.Serializable
DesignPatterns