原型模式
原型模式(Prototype Pattern)是一种创建型设计模式,允许一个对象再创建另外一个可定制的对象,无需知道如何创建的细节。即用原型实例指定创建对象的种类,并且通过拷贝这些原型,创建新的对象。
-
Prototype抽象原型类,声明了clone方法,它可以是接口或基类,可以不用抽象原型类。因为万物皆对象,在Java中Object类是所有类的父类,Object类中有clone方法。
-
ConcretePrototype具体原型类,实现或者重写clone方法
原型模式的克隆分为浅克隆和深克隆。
-
浅克隆 复制的变量和原变量的值相同,复制的引用仍指向原有的对象。
-
深克隆 复制的变量和原变量的值相同,复制的引用将指向被复制的新对象。
浅克隆
由于 Java 提供了对象的 clone 方法,所以用 Java 实现原型模式很简单。
在 java 中自定义类必须实现 Cloneable 接口,并重写 Object 类中的 clone 方法。
public class Student implements Cloneable {
public String name;
public int age;
public Dog dog;
@Override
protected Object clone() throws CloneNotSupportedException {
return (Student)super.clone();
}
public Student(String name, int age, Dog dog) {
this.name = name;
this.age = age;
this.dog = dog;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", dog=" + dog +
'}';
}
}
public class Dog {
private String name;
private int age;
public Dog(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Dog{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
public class PrototypeTest {
public static void main(String[] args)throws CloneNotSupportedException {
Student stu1 = new Student("张三",18,new Dog("dog",2));
Student stu2 = (Student)stu1.clone();
System.out.println(stu1);//Student{name='张三', age=18, dog=Dog{name='dog', age=2}}
System.out.println(stu2);//Student{name='张三', age=18, dog=Dog{name='dog', age=2}}
System.out.println(stu1 == stu2); //false
System.out.println(stu1.dog == stu2.dog); //true
}
}
通过运行结果发现浅拷贝出来引用类型Dog为同一个对象,若一个对象修改了属性势必会影响其它拷贝对象。
如果通过重写 clone() 方法去实现深克隆十分麻烦,需要将Dog类也实现clong()方法并在Student类的clone()中调用 Dog类的clong()因此引出了另外一种方式:序列化实现深克隆。
深克隆
在Java语言里深复制一个对象,常常可以先使对象实现 Serializable 接口,然后把对象(实际上只是对象的一个拷贝)写到一个流里,再从流里读出来,便可以重建对象。
public class Student implements Serializable {
public String name;
public int age;
public Dog dog;
protected Object deepClone() {
//创建流对象
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);
Student student = (Student) ois.readObject();
return student;
} catch (Exception e) {
e.printStackTrace();
return null;
} finally {
//关闭流
try {
bos.close();
oos.close();
bis.close();
ois.close();
} catch (Exception e2) {
System.out.println(e2.getMessage());
}
}
}
public Student(String name, int age, Dog dog) {
this.name = name;
this.age = age;
this.dog = dog;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", dog=" + dog +
'}';
}
}
public class Dog implements Serializable {
private String name;
private int age;
public Dog(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Dog{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
public class PrototypeTest {
public static void main(String[] args)throws CloneNotSupportedException {
Student stu1 = new Student("张三",18,new Dog("dog",2));
Student stu2 = (Student)stu1.deepClone();
System.out.println(stu1);// Student{name='张三', age=18, dog=Dog{name='dog', age=2}}
System.out.println(stu2);//Student{name='张三', age=18, dog=Dog{name='dog', age=2}}
System.out.println(stu1 == stu2); //false
System.out.println(stu1.dog == stu2.dog); //false
}
}