• 【Java 设计模式】创建者模式 之原型模式


    §1 定义

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

    §2 角色

    • 抽象原型类:定义具体原型类需要实现的 clone 方法,对于 Java 来说,具体原型类直接实现 Cloneable 接口重写 clone 方法即可,无需再重新定义抽象原型类。
    • 具体原型类:实现抽象原型类的 clone 方法。
    • 访问类:使用具体原型类中的 clone 方法复制新对象。

    §3 三好学生案例

    • 班级里有多名同学获得了三好学生的奖状,除了奖状上的获奖人姓名不一样外,其他都是一样的,使用原型模式复制出多个三好学生奖状,然后修改奖状上的名字。

    §3.1 浅克隆实现

    §3.1.1 浅克隆定义

    • 创建一个新的对象,新对象的属性和原型对象的完全相同,对于非基本类型的属性,仍然指向原型对象所指向的对象的内存地址

    §3.1.2 类图

    在这里插入图片描述

    §3.1.3 实现

    // 具体原型类: 奖状
    public class Citation implements Cloneable {
        private String name;
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public void show() {
            System.out.println("三好学生:" + name);
        }
        @Override
        protected Citation clone() throws CloneNotSupportedException {
            return (Citation) super.clone();
        }
    }
    
    // 访问类
    public class CitationTest {
        public static void main(String[] args) throws CloneNotSupportedException {
            Citation c1 = new Citation();
            c1.setName("张三");
            Citation c2 = c1.clone();
            c2.setName("李四");
            c1.show();
            c2.show();
        }
    }
    /* 输出结果:
    三好学生:张三
    三好学生:李四
    */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 浅克隆模式看似一切正常,若我们把 Citation 的 name 属性改为 Student 自定义对象,再来看看会发生什么?
    // 学生类
    public class Student {
        private String name;
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
    }
    
    // 具体原型类: 奖状
    public class Citation implements Cloneable {
        private Student student;
        public Student getStudent() {
            return student;
        }
        public void setStudent(Student student) {
            this.student = student;
        }
        public void show() {
            System.out.println("三好学生:" + student.getName());
        }
        @Override
        protected Citation clone() throws CloneNotSupportedException {
            return (Citation) super.clone();
        }
    }
    
    // 访问类
    public class CitationTest {
        public static void main(String[] args) throws CloneNotSupportedException {
            Citation c1 = new Citation();
            Student student1 = new Student();
            student1.setName("张三");
            c1.setStudent(student1);
            Citation c2 = c1.clone();
            Student student2 = c2.getStudent();
            student2.setName("李四");
            System.out.println("student1和student2是同一个对象吗?" + (student1 == student2));
            c1.show();
            c2.show();
        }
    }
    /* 输出结果:
    student1和student2是同一个对象吗?true
    三好学生:李四
    三好学生:李四
    */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 测试结果可以看出,两个 student 对象是同一个对象,当修改克隆后的学生名字时,原型对象的名字也被修改了,这是浅克隆方式的弊端。可以使用深克隆方式解决。

    §3.2 深克隆实现

    §3.2.1 深克隆定义

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

    §3.2.2 实现

    // 学生类
    public class Student implements Serializable {
        private String name;
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
    }
    
    // 具体原型类: 奖状
    public class Citation implements Cloneable, Serializable {
        private Student student;
        public Student getStudent() {
            return student;
        }
        public void setStudent(Student student) {
            this.student = student;
        }
        public void show() {
            System.out.println("三好学生:" + student.getName());
        }
        @Override
        protected Citation clone() throws CloneNotSupportedException {
            return (Citation) super.clone();
        }
    }
    
    // 访问类
    public class CitationTest {
        public static void main(String[] args) throws Exception {
            Citation c1 = new Citation();
            Student student1 = new Student();
            student1.setName("张三");
            c1.setStudent(student1);
            ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("D:\\study\\a.txt"));
            oos.writeObject(c1);
            oos.close();
            ObjectInputStream ois = new ObjectInputStream(new FileInputStream("D:\\study\\a.txt"));
            Citation c2 = (Citation) ois.readObject();
            ois.close();
            Student student2 = c2.getStudent();
            student2.setName("李四");
            System.out.println("student1和student2是同一个对象吗?" + (student1 == student2));
            c1.show();
            c2.show();
        }
    }
    /* 输出结果:
    student1和student2是同一个对象吗?false
    三好学生:张三
    三好学生:李四
    */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 使用序列化和反序列化的方式实现深克隆,解决浅克隆的弊端。
  • 相关阅读:
    AI-GruNet降噪算法
    HTTP/2的三大改进:头部压缩、多路复用和服务器推送
    高薪程序员&面试题精讲系列145之前后端如何交互?Swagger你用过吗?
    22.3 分布式
    论文解读(GCA)《Graph Contrastive Learning with Adaptive Augmentation》
    Matlab图像处理-
    提高采购效率,采购管理的五大原则及实现方法
    实践和项目:解决实际问题时,选择合适的数据结构和算法
    自动化防火墙放行目标域名IP
    局域网内无网络使用pip安装python3插件
  • 原文地址:https://blog.csdn.net/Coder_Farmer/article/details/128062260