指定创建对象的种类,并且通过拷贝这些原型,创建新的对象,是一种创建型设计模式,允许一个对象再创建另外一个可定制的对象,无需知道如何创建的细节。这种模式现了一个原型接口,该接口用于创建当前对象的克隆。
原型模式的构成:
- Prototype : 原型类,声明一个克隆自己的接口
- ConcretePrototype: 具体的原型类, 实现一个克隆自己的操作
- Client: 让一个原型对象克隆自己,从而创建一个新的对象(属性一样)
//克隆羊
public class Sheep implements Cloneable{
private String name;
private int age;
public Country country; //对象, 克隆是会如何处理, 默认是浅拷贝
public Sheep(String name, int age,Country country) {
this.name = name;
this.age = age;
this.country = country;
}
@Override
protected Object clone() {
Sheep sheep = null;
try {
sheep = (Sheep)super.clone();
}catch (Exception e){
System.out.println(e.getMessage());
}
return sheep;
}
@Override
public String toString() {
return "Sheep{" +
"name='" + name + '\'' +
", age=" + age +
", country=" + country +
", countryHashCode=" + country.hashCode() +
'}';
}
//省略 getter/setter
}
public class Country implements Cloneable{
private String name;
@Override
protected Object clone() {
Country country = null;
try {
country = (Country)super.clone();
}catch (Exception e){
System.out.println(e.getMessage());
}
return country;
}
@Override
public String toString() {
return "Country{" +
"name='" + name + '\'' +
'}';
}
//省略 getter/setter
}
public class Client {
public static void main(String[] args) {
Sheep sheep = new Sheep("多利羊", 3,new Country("美国"));
Sheep sheep1 = (Sheep)sheep.clone();
Sheep sheep2 = (Sheep)sheep.clone();
Sheep sheep3 = (Sheep)sheep.clone();
Sheep sheep4 = (Sheep)sheep.clone();
System.out.println("sheep1 =" + sheep1 );
System.out.println("sheep2 =" + sheep2 );
System.out.println("sheep3 =" + sheep3 );
System.out.println("sheep4 =" + sheep4 );
}
}
//输出:
//sheep1 =Sheep{name='多利羊', age=3, country=Country{name='美国'}, countryHashCode=356573597}
//sheep2 =Sheep{name='多利羊', age=3, country=Country{name='美国'}, countryHashCode=356573597}
//sheep3 =Sheep{name='多利羊', age=3, country=Country{name='美国'}, countryHashCode=356573597}
//sheep4 =Sheep{name='多利羊', age=3, country=Country{name='美国'}, countryHashCode=356573597}
基本数据类型的成员变量:
- 浅拷贝:直接进行值传递,该属性值复制一份给新的对象。
- 深拷贝:直接进行值传递,该属性值复制一份给新的对象。
引用数据类型的成员变量:
- 浅拷贝:将该成员变量的引用值(内存地址)复制一份给新的对象。
- 深拷贝:创建一个新对象,赋值。
//方法一:将 Sheep 的 clone 修改为如下
@Override
protected Object clone() {
Sheep sheep = null;
try {
sheep = (Sheep)super.clone();
//对象修改为可 clone
sheep.setCountry((Country)this.country.clone());
} catch (Exception e){
System.out.println(e.getMessage());
}
return sheep;
}
//输出:
//sheep1 =Sheep{name='多利羊', age=3, country=Country{name='美国'}, countryHashCode=356573597}
//sheep2 =Sheep{name='多利羊', age=3, country=Country{name='美国'}, countryHashCode=1735600054}
//sheep3 =Sheep{name='多利羊', age=3, country=Country{name='美国'}, countryHashCode=21685669}
// =Sheep{name='多利羊', age=3, country=Country{name='美国'}, countryHashCode=2133927002}
//方法二:使用序列化
public class DeepSheep implements Serializable, Cloneable{
private String name;
private int age;
public Country country; //对象, 克隆是会如何处理, 默认是浅拷贝
public DeepSheep(String name, int age, Country country) {
this.name = name;
this.age = age;
this.country = country;
}
@Override
protected Object clone() {
DeepSheep sheep = null;
try {
sheep = deepClone();
//sheep = SerializationUtils.deepCopy(this);
}catch (Exception e){
System.out.println(e.getMessage());
}
return sheep;
}
public DeepSheep deepClone() throws IOException,ClassNotFoundException{
//将对象写入流中
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream);
objectOutputStream.writeObject(this);
//从流中取出
ByteArrayInputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());
ObjectInputStream objectInputStream = new ObjectInputStream(inputStream);
return (DeepSheep)objectInputStream.readObject();
}
@Override
public String toString() {
return "Sheep{" +
"name='" + name + '\'' +
", age=" + age +
", country=" + country +
", countryHashCode=" + country.hashCode() +
'}';
}
//省略 getter/setter
}
public class Client {
public static void main(String[] args) {
DeepSheep deepSheep = new DeepSheep("汤姆羊", 3,new Country("法国"));
DeepSheep deepSheep1 = (DeepSheep)deepSheep.clone();
DeepSheep deepSheep2 = (DeepSheep)deepSheep.clone();
DeepSheep deepSheep3 = (DeepSheep)deepSheep.clone();
DeepSheep deepSheep4 = (DeepSheep)deepSheep.clone();
System.out.println("deepSheep1 =" + deepSheep1 );
System.out.println("deepSheep2 =" + deepSheep2 );
System.out.println("deepSheep3 =" + deepSheep3 );
System.out.println("deepSheep4 =" + deepSheep4 );
}
}
//deepSheep1 =Sheep{name='汤姆羊', age=3, country=Country{name='法国'}, countryHashCode=1531448569}
//deepSheep2 =Sheep{name='汤姆羊', age=3, country=Country{name='法国'}, countryHashCode=1867083167}
//deepSheep3 =Sheep{name='汤姆羊', age=3, country=Country{name='法国'}, countryHashCode=1915910607}
//deepSheep4 =Sheep{name='汤姆羊', age=3, country=Country{name='法国'}, countryHashCode=284720968}
//深拷贝工具类
public class SerializationUtils {
public static <T> T deepCopy(T src) throws IOException, ClassNotFoundException {
ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(byteOut);
out.writeObject(src);
ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray());
ObjectInputStream in = new ObjectInputStream(byteIn);
@SuppressWarnings("unchecked")
T dest = (T) in.readObject();
return dest;
}
}
-
创建新的对象比较复杂时,可以利用原型模式简化对象的创建过程,同时也能够提高效率
-
不用重新初始化对象,而是动态地获得对象运行时的状态
-
如果原始对象发生变化(增加或者减少属性),其它克隆对象的也会发生相应的变化,无需修改代码
-
在实现深克隆的时候可能需要比较复杂的代码
-
缺点:需要为每一个类配备一个克隆方法,这对全新的类来说不是很难,但对已有的类进行改造时,需要修改其源代码,违背了 ocp 原则,这点请同学们注意.