• 大话设计模式读书笔记(原型模式)


    人物:小菜,大鸟

    事件:小菜正在准备求职见面会,打印了很多简历,大鸟让小菜试着用程序写简历


    了解原型模型:

    1.通过用原始的逻辑实现几份相同简历的打印

    2.思考有没有一种模型可以帮助小菜不用新建对象,直接复制简历 --引出原型模型

    3.通过试验值复制和引用复制,知道了深复制和浅复制,然后引出深复制的实现原理和实现内容

    小菜简历代码初步实现

    简历类:

    @Slf4j
    public class Resume {
        private String name;
        private String sex;
        private String age;
        private String timeArea;
        private String company;
    
        public Resume(String name) {
            this.name = name;
        }
    
        /**
         * 设置个人信息
         *
         * @param sex
         * @param age
         */
        public void setPersonalInfo(String sex, String age) {
            this.sex = sex;
            this.age = age;
        }
    
        /**
         * 设置工作经历
         *
         * @param timeArea
         * @param company
         */
        public void setWorkExperience(String timeArea, String company) {
            this.timeArea = timeArea;
            this.company = company;
        }
    
        /**
         * 显示
         */
        public void display() {
            log.info("名字:{} 性别:{} 年龄:{}", name, sex, age);
            log.info("工作经历:{}, {}", timeArea, company);
        }
    }

    打印三份,客户端调用代码:

    public class ResumeDisplay {
        public static void main(String[] args) {
            Resume a = new Resume("大鸟");
            Resume b = new Resume("大鸟");
            Resume c = new Resume("大鸟");
            a.setPersonalInfo("男", "29");
            b.setPersonalInfo("男", "29");
            c.setPersonalInfo("男", "29");
            a.setWorkExperience("2019-2020", "凡人修仙公司");
            b.setWorkExperience("2019-2020", "凡人修仙公司");
            c.setWorkExperience("2019-2020", "凡人修仙公司");
            a.display();
            b.display();
            c.display();
        }
    }

    大鸟:这样如果要打印20份,也就要实例20个对象,如果写好20份后,如果要改下年份,那不是20个要一个一个改么?你其实可以先这样改下:

    public class ResumeDisplay {
        public static void main(String[] args) {
            Resume a = new Resume("大鸟");
            a.setPersonalInfo("男", "29");
            a.setWorkExperience("2018-2020", "凡人修仙公司");
            Resume b = a;
            Resume c = a;
            a.display();
            b.display();
            c.display();
        }
    }

    大鸟:这样就比刚才好多了,其实是传引用,不是传值,就像一份简历,每次复制与内容有关,与用什么纸无关,下面我们就可以开始了解原型模型了

    简历的原型模型实现

    原型模型:用原型模型指定创建对象的种类,并通过拷贝这些原型创建新的对象(而且不用知道创建的细节)

    简历类:

    @Slf4j
    public class Resume implements Cloneable {
        private String name;
        private String sex;
        private String age;
        private String timeArea;
        private String company;
    
        public Resume(String name) {
            this.name = name;
        }
    
        /**
         * 设置个人信息
         *
         * @param sex
         * @param age
         */
        public void setPersonalInfo(String sex, String age) {
            this.sex = sex;
            this.age = age;
        }
    
        /**
         * 设置工作经历
         *
         * @param timeArea
         * @param company
         */
        public void setWorkExperience(String timeArea, String company) {
            this.timeArea = timeArea;
            this.company = company;
        }
    
        /**
         * 显示
         */
        public void display() {
            log.info("名字:{} 性别:{} 年龄:{}", name, sex, age);
            log.info("工作经历:{}, {}", timeArea, company);
        }
    
        @Override
        public Object clone() {
            Resume resume = null;
            try {
                resume = (Resume) super.clone();
            } catch (CloneNotSupportedException e) {
                e.printStackTrace();
            }
            return resume;
        }
    }

    客户端调用:

    @Slf4j
    public class ResumeDisplay {
        public static void main(String[] args) {
            Resume a = new Resume("大鸟");
            a.setPersonalInfo("男", "29");
            a.setWorkExperience("2019-2020", "凡人修仙功法公司");
    
            Resume b = (Resume) a.clone();
            b.setWorkExperience("2020-2021", "凡人修仙宝器公司");
    
            Resume c = (Resume) a.clone();
            c.setWorkExperience("2020-2021", "凡人修仙炼体公司");
    
            a.display();
            b.display();
            c.display();
        }
    }

    大鸟:对的,这样实现后,这样每次复制简历或者要修改简历,都是直接克隆,而不是再去创建一个新的实例,大大提高了性能,还隐藏了实现的细节

    大鸟:但注意了,我们刚才复制的,都是String类型,也就是都是值类型,但如果是引用类型,就只会复制引用,不会复制引用的类型,因此原始对象及其复本引用同一对象

    如下:

    @Slf4j
    @Data
    public class Resume implements Cloneable {
        private String name;
        private String sex;
        private String age;
        private String timeArea;
        private String company;
        private WorkExperience work;
    
        public Resume(String name) {
            this.name = name;
            work = new WorkExperience();
        }
    
        /**
         * 设置个人信息
         *
         * @param sex
         * @param age
         */
        public void setPersonalInfo(String sex, String age) {
            this.sex = sex;
            this.age = age;
        }
    
        /**
         * 设置工作经历
         *
         * @param timeArea
         * @param company
         */
        public void setWorkExperience(String timeArea, String company) {
            work.setTimeArea(timeArea);
            work.setCompany(company);
        }
    
        /**
         * 显示
         */
        public void display() {
            log.info("名字:{} 性别:{} 年龄:{}", name, sex, age);
            log.info("工作经历:{}, {}", work.getTimeArea(), work.getCompany());
        }
    
        @Override
        public Object clone() {
            Resume resume = null;
            try {
                resume = (Resume) super.clone();
            } catch (CloneNotSupportedException e) {
                e.printStackTrace();
            }
            return resume;
        }
    }

    其中:private WorkExperience work是引用工作类型的对象

    在简历实例化时,同时实例化工作经历:

    public Resume(String name) {
        this.name = name;
        work = new WorkExperience();
    }

    在设置工作经历时,给对象的两属性值赋值:

    /**
     * 设置工作经历
     *
     * @param timeArea
     * @param company
     */
    public void setWorkExperience(String timeArea, String company) {
        work.setTimeArea(timeArea);
        work.setCompany(company);
    }

    这时如果再执行之前的客户端代码,则都只显示a对象的信息

    大鸟小结:如果是值对象,直接复制没有问题,如果是引用类型,只是复制了引用,对引用的对象还是指向了原来的对象,这叫做浅复制。浅复制指被复制对象的所有变量都含有与原来对象相同的值,而所有的对其他对象的引用都仍然指向原来的对象。当我们需要把所有引用的对象都复制一遍时,这就需要深复制,深复制会把引用对象的变量指向复制过的新对象,而不是原有的被引用的对象

    深复制:

    现在工作经历类中,复制传进来的值:

    @Data
    public class WorkExperience implements Cloneable {
        private String timeArea;
        private String company;
    
        public Object cloneInfo() {
            Object object = null;
            try {
                object = (Object)this.clone();
            } catch (CloneNotSupportedException e) {
                e.printStackTrace();
            }
            return object;
        }
    }

    然后在简历类中,先将传进来的工作经历复制,将a里工作经历的内容重新赋值后传了一个新对象给b,b也就得到了改变的值:

    @Slf4j
    @Data
    public class Resume implements Cloneable {
        private String name;
        private String sex;
        private String age;
        private String timeArea;
        private String company;
        private WorkExperience work;
    
        public Resume(String name) {
            this.name = name;
            work = new WorkExperience();
        }
    
        /**
         * 设置个人信息
         *
         * @param sex
         * @param age
         */
        public void setPersonalInfo(String sex, String age) {
            this.sex = sex;
            this.age = age;
        }
    
        /**
         * 设置工作经历
         *
         * @param timeArea
         * @param company
         */
        public void setWorkExperience(String timeArea, String company) {
            work.setTimeArea(timeArea);
            work.setCompany(company);
        }
    
        /**
         * 显示
         */
        public void display() {
            log.info("名字:{} 性别:{} 年龄:{}", name, sex, age);
            log.info("工作经历:{}, {}", work.getTimeArea(), work.getCompany());
        }
    
        @Override
        public Object clone() {
            Resume obj = new Resume(this.work);
            obj.name = this.name;
            obj.sex = this.sex;
            obj.age = this.age;
            return obj;
        }
    
        private Resume(WorkExperience work) {
            try {
                this.work = (WorkExperience)work.cloneInfo();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    这样得到的结果就不像浅复制一样都是一样的了,而是:

    名字:大鸟 性别:男 年龄:29
    工作经历:2019-2020, 凡人修仙功法公司
    名字:大鸟 性别:男 年龄:29
    工作经历:2020-2021, 凡人修仙宝器公司
    名字:大鸟 性别:男 年龄:29
    工作经历:2020-2021, 凡人修仙炼体公司
    名字:大鸟 性别:男 年龄:29
  • 相关阅读:
    c语言面试基础题
    fwrite(&stud[i],sizeof(struct student_type),1,fp)的基本含义
    对于文件操作函数的记录
    将字符串s1复制到字符串s2。
    将键盘输入的几个数据存储到文件里的程序
    利用指针对二维数组进行遍历查找程序
    常见的C语言错误及程序的调试
    文件的基本操作函数及说明
    一个磁盘信息向另一个磁盘信息的复制
    常用流程图符号和基本流程图
  • 原文地址:https://www.cnblogs.com/wencheng9012/p/13392730.html
Copyright © 2020-2023  润新知