原型模式

原型模式

参考资料地址: 原型模式(浅克隆与深克隆)

概述

创建型模式

用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型对象相同的新对象

使用场景

  • 对象的创建非常复杂,可以使用原型模式快捷的创建对象。

  • 性能和安全要求比较高。

实现

原型模式的克隆分为浅克隆和深克隆

  • 浅克隆:创建一个新对象,新对象的属性和原来对象完全相同,对于非基本类型属性,任指向原有属性所指向的对象的内存地址

  • 深克隆:创建一个新对象,属性中引用的其他对象也会被克隆,不再指向原有对象的地址

注意:

基本类型的包装类和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未克隆,所以地址值一样,其他同上

posted @ 2022-03-30 14:39  进击的小蔡鸟  阅读(27)  评论(0编辑  收藏  举报