一、原型模式的定义
Specifythekindsofobjectstocreateusingaprototypicalinstance,andcreatenewobjectsbycopyingthisprototype.(用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。)
二、原型模式的应用
1、原型模式的优点
性能优良原型模式是在内存二进制流的拷贝,要比直接new一个对象性能好很多,特别是要在一个循环体内产生大量的对象时,原型模式可以更好地体现其优点。
逃避构造函数的约束这既是它的优点也是缺点,直接在内存中拷贝,构造函数是不会执行的。优点就是减少了约束,缺点也是减少了约束,需要大家在实际应用时考虑。
2、原型模式的缺点
需要为每个类配备一个克隆方法,而且该克隆方法位于这个类里面,当对已有的类进行改造时需要修改源代码,违背了开闭原则
在实现深度克隆的时需要编写较为复杂的代码,而且当对象之间存在多重嵌套引用的时候,为了实现深度克隆,每一层对象的类都必须支持深度克隆,实现起来比较麻烦!
3、原型模式的使用场景
资源优化场景类初始化需要消化非常多的资源,这个资源包括数据、硬件资源等。
性能和安全要求的场景通过new产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模式。
一个对象多个修改者的场景一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以考虑使用原型模式拷贝多个对象供调用者使用。在实际项目中,原型模式很少单独出现,一般是和工厂方法模式一起出现,通过clone的方法创建一个对象,然后由工厂方法提供给调用者。原型模式已经与Java融为一体,大家可以随手拿来使用。
三、原型模式的写法
重写clone实现深拷贝
public class DeepCloneable {
public static void main(String[] args) throws CloneNotSupportedException {
DeepObject deepObject = new DeepObject("deepName");
deepObject.setCloneObjece(new CloneObjece("cloneObjeceName"));
//两次输出hashcode不一致
System.out.println(deepObject.getCloneObjece().hashCode());
DeepObject cloneDeepObject = (DeepObject)deepObject.clone();
System.out.println(cloneDeepObject.getCloneObjece().hashCode());
}
}
class DeepObject implements Cloneable{
private String deepName;
private CloneObjece cloneObjece;
public DeepObject(String deepName) {
this.deepName = deepName;
}
public CloneObjece getCloneObjece() {
return cloneObjece;
}
public void setCloneObjece(CloneObjece cloneObjece) {
this.cloneObjece = cloneObjece;
}
@Override
public String toString() {
return "DeepObject [deepName=" + deepName + ", cloneObjece=" + cloneObjece + "]";
}
// 深拷贝方式一:使用clone方法
@Override
protected Object clone() throws CloneNotSupportedException {
Object clone = super.clone();
DeepObject cloneDeepObject = (DeepObject)clone;
cloneDeepObject.setCloneObjece((CloneObjece)cloneDeepObject.getCloneObjece().clone());
return cloneDeepObject;
}
}
class CloneObjece implements Cloneable{
private String cloneObjeceName;
public CloneObjece(String cloneObjeceName) {
this.cloneObjeceName = cloneObjeceName;
}
@Override
public String toString() {
return "CloneObjece [cloneObjeceName=" + cloneObjeceName + "]";
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
对象序列化实现深拷贝
public class DeepCloneable {
public static void main(String[] args) throws CloneNotSupportedException {
DeepObject deepObject = new DeepObject("deepName");
deepObject.setCloneObjece(new CloneObjece("cloneObjeceName"));
//两次输出hashcode不一致
System.out.println(deepObject.getCloneObjece().hashCode());
DeepObject cloneDeepObject = (DeepObject)deepObject.deepClone();
System.out.println(cloneDeepObject.getCloneObjece().hashCode());
}
}
class DeepObject implements Serializable{
private static final long serialVersionUID = 1L;
private String deepName;
private CloneObjece cloneObjece;
public DeepObject(String deepName) {
this.deepName = deepName;
}
public CloneObjece getCloneObjece() {
return cloneObjece;
}
public void setCloneObjece(CloneObjece cloneObjece) {
this.cloneObjece = cloneObjece;
}
@Override
public String toString() {
return "DeepObject [deepName=" + deepName + ", cloneObjece=" + cloneObjece + "]";
}
// 方式二 序列化
public Object deepClone() {
Object obj = null;
// 准备流对象
ByteArrayOutputStream bos = null;
ObjectOutputStream oos = null;
ByteArrayInputStream bis = null;
ObjectInputStream ois = null;
try {
// 生成流对象,并进行序列化
bos = new ByteArrayOutputStream();
oos = new ObjectOutputStream(bos);
oos.writeObject(this);
// 反序列化
bis = new ByteArrayInputStream(bos.toByteArray());
ois = new ObjectInputStream(bis);
obj = ois.readObject();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}finally {
// 关闭流
try {
if(ois != null)
ois.close();
if(bis != null)
bis.close();
if(oos != null)
oos.close();
if(bos != null)
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return obj;
}
}
class CloneObjece implements Serializable{
private static final long serialVersionUID = 1L;
private String cloneObjeceName;
public CloneObjece(String cloneObjeceName) {
this.cloneObjeceName = cloneObjeceName;
}
@Override
public String toString() {
return "CloneObjece [cloneObjeceName=" + cloneObjeceName + "]";
}
}
四、原型模式在源码中的应用
@Override
public Object clone() {
return new Intent(this);
}
/**
* Copy constructor.
*/
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;
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);
}
}
可以看到,clone方法实际上在内部调用了new Intent(this); 而且是深拷贝。