大话设计模式——8.原型模式(Prototype Pattern)

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
     */
    @Override
    protected 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;
    }

    @Override
    public 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. 深克隆的实现编写较为复杂,且对象间存在多重嵌套引用时,其中的每个必须支持深克隆。

相关推荐

  1. 大话设计模式

    2024-03-18 01:36:01       21 阅读
  2. 设计模式8原则

    2024-03-18 01:36:01       25 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-03-18 01:36:01       98 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-03-18 01:36:01       106 阅读
  3. 在Django里面运行非项目文件

    2024-03-18 01:36:01       87 阅读
  4. Python语言-面向对象

    2024-03-18 01:36:01       96 阅读

热门阅读

  1. Leetcode--12

    2024-03-18 01:36:01       43 阅读
  2. 【Linux笔记-使用指南-备忘录】

    2024-03-18 01:36:01       41 阅读
  3. excel封装和ddt D17

    2024-03-18 01:36:01       43 阅读
  4. [蓝桥杯 2020 省 AB1] 走方格

    2024-03-18 01:36:01       38 阅读
  5. nuxtjs 如何通过ecosystem.config.js配置pm2?

    2024-03-18 01:36:01       38 阅读
  6. 解释 Git 的基本概念和使用方式。

    2024-03-18 01:36:01       39 阅读
  7. Linux之Shell脚本

    2024-03-18 01:36:01       39 阅读
  8. 2023蓝桥杯省赛真题分糖果 |枚举+DFS

    2024-03-18 01:36:01       54 阅读
  9. HTML与CSS

    2024-03-18 01:36:01       45 阅读
  10. 前端开发者如何开发自己的生态网站

    2024-03-18 01:36:01       34 阅读
  11. Rust 01.变量、类型、函数

    2024-03-18 01:36:01       34 阅读