原型模式
原型模式
概述
创建型模式
用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型对象相同的新对象
使用场景
对象的创建非常复杂,可以使用原型模式快捷的创建对象。
实现
原型模式的克隆分为浅克隆和深克隆
浅克隆:创建一个新对象,新对象的属性和原来对象完全相同,对于非基本类型属性,任指向原有属性所指向的对象的内存地址
深克隆:创建一个新对象,属性中引用的其他对象也会被克隆,不再指向原有对象的地址
注意:
基本类型的包装类和String类型的属性,虽然克隆出来的属性指向同一个内存地址,但克隆出来的属性改变并不会影响原来被克隆对象的属性(原因:赋值时,引用对象属性的地址值已发生变化)
原理:基本类型和引用类型的区别
在原有的引用对象属性上修改会影响其他的克隆对象,如(student);
如果给原有的引用对象属性赋一个新的引用对象,则不会影响,如classroom.
浅克隆
奖状实体类
/** * 奖状 * 描述: 克隆对象实例 * * @author lyn * @date 2022/3/30 11:07 */ @Data @NoArgsConstructor @AllArgsConstructor public class Citation implements Cloneable { /** * 学生 */ private Student student; /** * 奖状级别 */ private Integer level; /** * 班级 */ private String classroom; /** * 评语 */ private String message; @Override public Citation clone() throws CloneNotSupportedException { return (Citation)super.clone(); } }
/** * 学生 * * @author lyn * @date 2022/3/30 13:13 */ @Data @AllArgsConstructor @NoArgsConstructor public class Student { /** * 姓名 */ private String name; /** * 地址 */ private String address; }
/** * 测试浅克隆 * @throws CloneNotSupportedException */ @Test public void testShallowClone() throws CloneNotSupportedException { Student student = new Student("张三","北京"); Citation citation = new Citation(student, 1, "三年级二班", "三好学生"); Citation citation1 = citation.clone(); System.out.println("两个对象是否相同;"+(citation==citation1)); System.out.println("两个对象的引用对象属性是否指向同一个内存地址"+(citation.getClassroom()==citation1.getClassroom())); citation1.setClassroom("三年级一班"); citation1.getStudent().setName("李四"); System.out.println(citation+"**--**"+citation1); }
两个对象是否相同;false 两个对象的引用对象属性是否指向同一个内存地址true Citation(student=Student(name=李四, address=北京), level=1, classroom=三年级二班, message=三好学生) Citation(student=Student(name=李四, address=北京), level=1, classroom=三年级一班, message=三好学生)
深克隆
通过序列化的方式实现深克隆
序列化(Serialization)就是将对象写到流的过程,写到流中的对象是原有的对象的一个拷贝,而原对象仍存在内存中。通过序列化实现的拷贝不仅可以复制对象本身,而且也可以复制其引用的成员对象,因此通过序列化将对象写入一个流中,再从流中将其读出来,从而实现深克隆
注意:
被克隆对象的引用对象属性也必须实现可序列化
奖状实体类
/** * 奖状 * 描述: 克隆对象实例 * * @author lyn * @date 2022/3/30 11:07 */ @Data @NoArgsConstructor @AllArgsConstructor public class Citation implements Serializable { private static final long serialVersionUID = 1L; /** * 姓名 */ private Student student; /** * 奖状级别 */ private Integer level; /** * 班级 */ private String classroom; /** * 评语 */ private String message; /** * 通过序列化的方式实现深克隆 * @return * @throws IOException * @throws ClassNotFoundException */ public Citation deepClone() throws IOException, ClassNotFoundException { //将对象写入流 ByteArrayOutputStream bao = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bao); oos.writeObject(this); //将对象从流中取出 ByteArrayInputStream bis = new ByteArrayInputStream(bao.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bis); return (Citation)ois.readObject(); } }
/** * 学生 * * @author lyn * @date 2022/3/30 13:13 */ @Data @AllArgsConstructor @NoArgsConstructor public class Student implements Serializable { private static final long serialVersionUID = 1L; /** * 姓名 */ private String name; /** * 地址 */ private String address; }
测试类
/** * 测试深克隆 * */ @Test public void testShallowClone() throws IOException, ClassNotFoundException { Student student = new Student("张三","北京"); Citation citation = new Citation(student, 1, "三年级二班", "三好学生"); Citation citation1 = citation.deepClone(); System.out.println("两个对象是否相同;"+(citation==citation1)); System.out.println("两个对象的引用对象属性是否指向同一个内存地址"+(citation.getStudent()==citation1.getStudent())); System.out.println("两个对象的引用对象属性是否指向同一个内存地址"+(citation.getMessage()==citation1.getMessage())); citation1.getStudent().setName("李四"); System.out.println(citation+"\n"+citation1); }
打印结果
两个对象是否相同;false 两个对象的引用对象属性是否指向同一个内存地址false 两个对象的引用对象属性是否指向同一个内存地址false Citation(student=Student(name=张三, address=北京), level=1, classroom=三年级二班, message=三好学生) Citation(student=Student(name=李四, address=北京), level=1, classroom=三年级二班, message=三好学生)
改造克隆代码
实现繁琐
奖状实体类
/** * 奖状 * 描述: 克隆对象实例 * * @author lyn * @date 2022/3/30 11:07 */ @Data @NoArgsConstructor @AllArgsConstructor public class Citation implements Cloneable { /** * 姓名 */ private Student student; /** * 奖状级别 */ private Integer level; /** * 班级 */ private String classroom; /** * 评语 */ private String message; @Override public Citation clone() throws CloneNotSupportedException { Citation citation=(Citation)super.clone(); citation.setStudent(citation.student.clone()); return citation; } }
学生实体类
/** * 学生 * * @author lyn * @date 2022/3/30 13:13 */ @Data @AllArgsConstructor @NoArgsConstructor public class Student implements Cloneable { /** * 姓名 */ private String name; /** * 地址 */ private String address; @Override public Student clone() throws CloneNotSupportedException { return (Student)super.clone(); } }
classroom未克隆,所以地址值一样,其他同上