1.介绍
用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。属于创建型模式。
UML图:
1)浅拷贝: 指创建一个新的对象,然后将原始对象的字段值复制到新对象中。如果字段是基本类型,直接复制其值;如果字段是引用类型,则复制其引用,新对象和原对象将共享同一份引用指向相同的内存地址。一般实现Cloneable接口,重写clone()方法。
2)深拷贝: 指创建一个新的对象,然后将原始对象的字段值复制到新对象中。但与浅拷贝不同的是,对于引用类型的字段,深拷贝会递归地复制其所指向的对象,而不是复制引用本身。一般实现Serializable接口进行序列化再反序列化。
2.示例
一个学校的学生信息有着许多可以复用的,因此可以使用原型模式进行设计,快速创建复用的信息。
1)学生对象:Student
public class Student implements Cloneable, Serializable {private String name;private String sex;/*** 年级*/private String grade;/*** 学校*/private String schoolName;/*** 学科*/private List<String> subjects;/*** 浅拷贝 ,调用顶级父类Object的方法** @return* @throws CloneNotSupportedException*/@Overrideprotected Student clone() throws CloneNotSupportedException {return (Student) super.clone();}/*** 深拷贝** @return*/public Student deepClone() {try {// 转换二进制输出流,序列化ByteArrayOutputStream bao = new ByteArrayOutputStream();ObjectOutputStream oos = new ObjectOutputStream(bao);oos.writeObject(this);// 输入流转换,反序列化,拷贝形成新的对象ByteArrayInputStream bai = new ByteArrayInputStream(bao.toByteArray());ObjectInputStream ois = new ObjectInputStream(bai);return (Student) ois.readObject();} catch (Exception e) {e.printStackTrace();return null;}}public Student() {}public Student(String name, String sex, String grade, String schoolName, List<String> subjects) {this.name = name;this.sex = sex;this.grade = grade;this.schoolName = schoolName;this.subjects = subjects;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getSex() {return sex;}public void setSex(String sex) {this.sex = sex;}public String getGrade() {return grade;}public void setGrade(String grade) {this.grade = grade;}public String getSchoolName() {return schoolName;}public void setSchoolName(String schoolName) {this.schoolName = schoolName;}public List<String> getSubjects() {return subjects;}public void setSubjects(List<String> subjects) {this.subjects = subjects;}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", sex='" + sex + '\'' +", grade='" + grade + '\'' +", schoolName='" + schoolName + '\'' +", subjects=" + subjects +'}';}
}
2)运行:
public class Main {public static void main(String[] args) throws CloneNotSupportedException {Student student1 = new Student("大美", "女", "一年级", "大大小学", Arrays.asList("数学", "语文", "英语"));// 浅拷贝Student student2 = student1.clone();student2.setName("小美");student2.getSubjects().set(1,"da");// 深拷贝Student student3 = student1.deepClone();student3.setName("小庄");student3.setSex("男");student3.getSubjects().set(1,"hh");System.out.println(student1);System.out.println(student2);System.out.println(student3);// 浅拷贝,引用类型数据指向共同的地址System.out.println(student2.getSubjects() == student1.getSubjects());System.out.println(student3.getSubjects() == student1.getSubjects());}
}
3.总结
1)优点:
a. 当创建新的对象实例较为复杂时,可以简化对象的创建过程,提高新实例的创建效率;
b. 可以辅助实现撤销操作,采取深克隆的方式保存对象的状态,将对象复制⼀份并将其状态保存起来,在需要的时候使其恢复到历史状态。
2)缺点:
a. 每个类都需要重写克隆方法,比较繁琐且不符合开闭原则;
b. 深克隆的实现编写较为复杂,且对象间存在多重嵌套引用时,其中的每个必须支持深克隆。