定义
将一个原型对象传给那个要发动创建的对象,这个要发动创建的对象通过请求原型对象拷贝自己来实现创建过程。由于在软件系统中我们经常会遇到需要创建多个相同或者相似对象的情况,因此原型模式在真实开发中的使用频率还是非常高的。原型模式是一种“另类”的创建型模式,创建克隆对象的工厂就是原型类自身,工厂方法由克隆方法来实现。
浅拷贝
在浅克隆中,如果原型对象的成员变量是值类型,将复制一份给克隆对象;如果原型对象的成员变量是引用类型,则将引用对象的地址复制一份给克隆对象,也就是说原型对象和克隆对象的成员变量指向相同的内存地址。
深拷贝
在深克隆中,无论原型对象的成员变量是值类型还是引用类型,都将复制一份给克隆对象,深克隆将原型对象的所有引用对象也复制一份给克隆对象。
UML类图
代码实现
浅拷贝
ShallowCustom.java
public class ShallowCustom {
private String name;
private int age;
public ShallowCustom(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
ShallowPrototype.java
public class ShallowPrototype implements Cloneable {
private String name;
private ShallowCustom custom;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public ShallowCustom getCustom() {
return custom;
}
public void setCustom(ShallowCustom custom) {
this.custom = custom;
}
public ShallowPrototype shallowClone() {
ShallowPrototype obj = null;
try {
obj = (ShallowPrototype) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return obj;
}
}
Main.java
ShallowCustom custom = new ShallowCustom("lisi", 18);
ShallowPrototype prototype = new ShallowPrototype();
prototype.setName("wangwu");
prototype.setCustom(custom);
ShallowPrototype prototypeNew = prototype.shallowClone();
Log.d("TAG", "object:"+(prototype == prototypeNew));
Log.d("TAG", "getName:"+(prototype.getName() == prototypeNew.getName()));
Log.d("TAG", "getCustom:"+(prototype.getCustom() == prototypeNew.getCustom()));
打印结果:
object:false
getName:true
getCustom:true
深拷贝
DeepCustom.java
public class DeepCustom implements Serializable {
private String name;
private int age;
public DeepCustom(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
DeepPrototype.java
public class DeepPrototype implements Serializable {
private String name;
private DeepCustom custom;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public DeepCustom getCustom() {
return custom;
}
public void setCustom(DeepCustom custom) {
this.custom = custom;
}
public DeepPrototype deepClone() {
DeepPrototype prototype = null;
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(DeepPrototype.this);
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
prototype = (DeepPrototype) ois.readObject();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return prototype;
}
}
Main.java
DeepCustom custom = new DeepCustom("lisi", 18);
DeepPrototype prototype = new DeepPrototype();
prototype.setName("wangwu");
prototype.setCustom(custom);
DeepPrototype prototypeNew = prototype.deepClone();
Log.d("TAG", "object:"+(prototype == prototypeNew));
Log.d("TAG", "getName:"+(prototype.getName() == prototypeNew.getName()));
Log.d("TAG", "getCustom:"+(prototype.getCustom() == prototypeNew.getCustom()));
打印结果:
object:false
getName:false
getCustom:false
优缺点
主要优点
-
当创建新的对象实例较为复杂时,使用原型模式可以简化对象的创建过程,通过复制一个已有实例可以提高新实例的创建效率。
-
扩展性较好,由于在原型模式中提供了抽象原型类,在客户端可以针对抽象原型类进行编程,而将具体原型类写在配置文件中,增加或减少产品类对原有系统都没有任何影响。
-
原型模式提供了简化的创建结构,工厂方法模式常常需要有一个与产品类等级结构相同的工厂等级结构,而原型模式就不需要这样,原型模式中产品的复制是通过封装在原型类中的克隆方法实现的,无须专门的工厂类来创建产品。
-
可以使用深克隆的方式保存对象的状态,使用原型模式将对象复制一份并将其状态保存起来,以便在需要的时候使用(如恢复到某一历史状态),可辅助实现撤销操作。
主要缺点
-
需要为每一个类配备一个克隆方法,而且该克隆方法位于一个类的内部,当对已有的类进行改造时,需要修改源代码,违背了“开闭原则”。
-
在实现深克隆时需要编写较为复杂的代码,而且当对象之间存在多重的嵌套引用时,为了实现深克隆,每一层对象对应的类都必须支持深克隆,实现起来可能会比较麻烦。