• 设计模式学习--原型模式


    原型模式(Prototype):用原型实例指定创建对象的 种类,并且通过拷贝这些原型创建新的对象。

    原型模式结构图:

    原型模式涉及深克隆和浅克隆。

    案例需求:制作一份简历,并复制三份。

    第一次克隆实现:

    1:创建简历类。

    package PrototypeModel;
    
    /**
     * 简历类
     * @author 我不是张英俊
     *
     */
    public class Resume implements Cloneable {
    
        private String name;
        private String sex;
        private String age;
        private String timeArea;
        private String company;
        
        public Resume(){
            
        }
        public Resume(String name){
            this.name=name;
        }
        
        //设置个人信息
        public void SetPersonalInfo(String sex,String age){
            this.sex=sex;
            this.age=age;
        }
        
        //设置工作经历
        public void SetWorkExperience(String timeArea,String company){
            this.timeArea=timeArea;
            this.company=company;
        }
        
        //显示
        public void Display(){
            System.out.println(name+"    "+sex+"    "+age);
            System.out.println("工作经历:"+timeArea+"    "+company);
        }
        
        public Object Copy() throws CloneNotSupportedException {
            return this;
        }    
        
        public Object clone() throws CloneNotSupportedException{
            //调用父类Object中的clone方法实现浅克隆
            return super.clone();
        }
    }

    2:创建测试类

    package PrototypeModel;
    
    /**
     * 简历复印,打印一份简历,并复印三份;
     * 原型模式:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
     * @author 我不是张英俊
     *
     */
    public class Test {
    
        public static void main(String[] args) throws CloneNotSupportedException {
    
            Resume a=new Resume("旺财");
            a.SetPersonalInfo("男", "19");
            a.SetWorkExperience("1998-2-3", "百度");
            
            /**
             * Cpoy 方法中的是return this,
             * 返回的是索引,即返回的是指向堆中a对象的索引,
             * 所以,不论怎么重新改变属性,最终改变的都是a对象中的属性,
             * 而此时,并没有在堆中重新copy出两个新的对象b和c。
             * 所以,应该用clone方法来实行,
             * 继承Cloneable接口,并且重写Object中的clone方法。
             * Cloneable接口是一个空的接口,它只是表明,可以重写clone方法,若不实现此接口,不可以重写clone方法
             * 此处使用的是浅克隆。
             */
            Resume b= (Resume) a.Copy();
            Resume b1=(Resume) a.clone();
            b.SetWorkExperience("2019-02-06", "360");
            
            Resume c=(Resume) a.Copy();
            Resume c1=(Resume) a.clone();
            a.SetWorkExperience("2016-03-02", "阿里");
            
            System.out.println("a=  "+a);
            System.out.println("b=  "+b);
            System.out.println("c=  "+c);
            System.out.println("b1= "+b1);
            System.out.println("c1= "+c1);
            /**
             * 控制台输出发现克隆的索引不同,即创建出了新的对象。
             */
            a.Display();
            b.Display();
            c.Display();
            
            a.Display();
            b1.Display();
            c1.Display();
        }
    
    }

    3:控制台

    a=  PrototypeModel.Resume@6a5c2445
    b=  PrototypeModel.Resume@6a5c2445
    c=  PrototypeModel.Resume@6a5c2445
    b1= PrototypeModel.Resume@47516490
    c1= PrototypeModel.Resume@30a14e84
    旺财    男    19
    工作经历:2016-03-02    阿里
    旺财    男    19
    工作经历:2016-03-02    阿里
    旺财    男    19
    工作经历:2016-03-02    阿里
    旺财    男    19
    工作经历:2016-03-02    阿里
    旺财    男    19
    工作经历:1998-2-3    百度
    旺财    男    19
    工作经历:2019-02-06    360

    a,b,c三个的地址相同,说明return this返回当前对象的时候返回的是索引,他们指向同一个对象。

    而b1,c1地址不同,说明是利用clone方法创建了新的对象。

    super.clone()返回的是Object类型的。利用Object类中的clone方法来进行浅克隆。重写Object类中的clone方法需要实现Cloneable接口。

    其中Cloneable接口是一个空接口,它只是表明你可以重写clone方法,不实现重写的话,会抛出异常。

    第二次克隆实现

    事实上在实际开发过程中,工作经历通常会做成工作经历类,这样,就需要深克隆。

    先看如果使用浅克隆导致的问题:

    1:创建工作经历类。

    package PrototypeModel2;
    
    public class workExperence {
    
        private String workDate;
        private String company;
        public String getWorkDate() {
            return workDate;
        }
        public void setWorkDate(String workDate) {
            this.workDate = workDate;
        }
        public String getCompany() {
            return company;
        }
        public void setCompany(String company) {
            this.company = company;
        }
    }

    2:创建简历类。

    package PrototypeModel2;
    
    public class Resume implements Cloneable {
    
        private String name;
        private String sex;
        private String age;
        private workExperence work;
         
        public Resume(String name){
            this.name=name;
            work=new workExperence();
        }
        
        //设置个人信息
        public void setPersonalInfo(String sex,String age){
            this.sex=sex;
            this.age=age;
        }
        
        //设置工作经历
        public void setWorkExperience(String workDate,String company){
            work.setCompany(company);
            work.setWorkDate(workDate);
        }
        //显示
        public void display(){
            System.out.println(name+"    "+sex+"    "+age);
            System.out.println(work.getCompany()+"      "+work.getWorkDate());
        }
        
        public Object clone() throws CloneNotSupportedException{
            return super.clone();
        }
    }

    3:测试类。

    package PrototypeModel2;
    
    /**
     * 浅克隆会导致的问题
     * 制作简历
     * 实际开发中,会将工作经历作为一个类,
     * @author 我不是张英俊
     *
     */
    public class Test {
    
        public static void main(String arg[]) throws CloneNotSupportedException{
            Resume a=new Resume("旺财");
            a.setPersonalInfo("男", "26");
            a.setWorkExperience("2016-1017", "阿里");
            
            Resume b=(Resume) a.clone();
            b.setWorkExperience("2017-2018", "360");
            
            Resume c=(Resume) a.clone();
            a.setWorkExperience("2018-2019", "腾讯");
            
            a.display();
            b.display();
            c.display();
        }
    }

    4:控制台。

    旺财    男    26
    腾讯      2018-2019
    旺财    男    26
    腾讯      2018-2019
    旺财    男    26
    腾讯      2018-2019

    原因:堆内存中只存在一个workExperience类,所以在修改的时候,总是修改同一个类中的数据,虽然克隆了不同的Resume对象,但不同的Resume对象确是调用同一个workExperience中的数据,所以最后输出的都是最后修改的。

    因为clone()方法,对于引用类型,克隆的是其引用,所以,当改变值得时候,就会出现相同的结果。因为三个引用都指向了同一个对象,即唯一的workExperience对象。

    如果想显示不同的,就必须对workExperience进行克隆,这样每一个引用不同的workExperience就不会出现这种问题。

    第三次克隆实现:

    1:创建工作经历类

    package PrototypeModel1;
    /**
     * 工作经历类
     * @author 我不是张英俊
     *
     */
    public class WorkExperience implements Cloneable {
    
        private String workDate;
        private String company;
        public String getWorkDate() {
            return workDate;
        }
        public void setWorkDate(String workDate) {
            this.workDate = workDate;
        }
        public String getCompany() {
            return company;
        }
        public void setCompany(String company) {
            this.company = company;
        }
        
        public Object clone() throws CloneNotSupportedException{
            return super.clone();
        }
    }

    2:创建一个简历类。

    package PrototypeModel1;
    
    public class Resume implements Cloneable {
    
        private String name ;
        private String sex;
        private String age;
        private WorkExperience work;
        
        public Resume(String name){
            this.name=name;
            work=new WorkExperience();
        }
        /*
         *提供clone方法调用的私有构造函数,以便克隆“工作经历”的数据 
         */
        private Resume(WorkExperience work) throws CloneNotSupportedException{
            this.work=(WorkExperience) work.clone();
        }
        
        //设置个人信息
        public void setPersonalInfo(String sex,String age){
            this.sex=sex;
            this.age=age;
        }
        
        //设置工作经历
        public void setWorkExperience(String workDate,String company){
            
            work.setCompany(company);
            work.setWorkDate(workDate);
        }
        
        //展示
        public void display(){
            System.out.println(name+"    "+sex+"    "+age);
            System.out.println("工作经历    "+work.getCompany()+"      "+work.getWorkDate());
        }
        
        public Object clone() throws CloneNotSupportedException{
            /**
             * 调用私有的构造方法,让“工作经历”克隆完成,然后再给这个“简历”
             * 对象相关字段赋值,最终返回一个深克隆的简历对象。
             */
            Resume obj=new Resume(this.work);
            obj.age=this.age;
            obj.name=this.name;
            obj.sex=this.sex;
            return obj;
        }
    }

    3:创建一个测试类。

    package PrototypeModel1;
    
    /**
     * 简历复印,
     * 原型模式,
     * 深拷贝和浅拷贝
     * @author 我不是张英俊
     *
     */
    public class Test {
    
        public static void main(String[] args) throws CloneNotSupportedException {
            Resume a =new Resume("旺财");
            a.setPersonalInfo("男", "19");
            a.setWorkExperience("2019-2020", "阿里");
            
            Resume b=(Resume)a.clone();
            b.setWorkExperience("2017-2018", "腾讯");
            
            Resume c=(Resume)a.clone();
            c.setWorkExperience("2016-2017", "华为");
            
            a.display();
            b.display();
            c.display();
        }
    
    }

    4:控制台。

    旺财 男 19
    工作经历 阿里 2019-2020
    旺财 男 19
    工作经历 腾讯 2017-2018
    旺财 男 19
    工作经历 华为 2016-2017

    利用深克隆解决问题。创建了堆内存中实际存在了三个workExperience对象。

    总结:理解尚浅,暂时未想到。

  • 相关阅读:
    HIVE中内连接和左半连接不一致问题
    hive 中的Sort By、 Order By、Cluster By、Distribute By 区别
    基于MapReduce的矩阵乘法运算
    基于MapReduce的关系代数运算(2)
    基于MapReduce的关系代数运算(1)
    帖子爬取
    tomcat------https单向认证和双向认证
    struts2配置文件struts.xml的简介
    2014,事情只有一件!
    MYSQLi数据访问查询数据
  • 原文地址:https://www.cnblogs.com/hrlizhi/p/7657199.html
Copyright © 2020-2023  润新知