• 原型模式


    在讲述这个模式之前,我们先看一个案例:复制简历

    先创建一个简历类

    public class Resume {
        private String name;
        private String sex;
        private String age;
        private String timeArea;
        private String company;
        
        public Resume(String name) {
            super();
            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("Resume [name=" + name + ", sex=" + sex + ", age=" + age + ", timeArea=" + timeArea + ", company="
                    + company + "]");
        }
    }

    测试方法

    public class Test {
        public static void main(String[] args) {
            Resume a = new Resume("张三");
            a.setPersonalInfo("男", "30");        
            a.setWorkExperience("1999-2000", "XX公司");
            
            Resume b = new Resume("张三");
            b.setPersonalInfo("男", "30");    
            b.setWorkExperience("1999-2000", "XX公司");
            
            Resume c = new Resume("张三");
            c.setPersonalInfo("男", "30");        
            c.setWorkExperience("1999-2000", "XX公司");
            
            a.display();
            b.display();
            c.display();
        }
    }

    输出结果

    Resume [name=张三, sex=男, age=30, timeArea=1999-2000, company=XX公司]
    Resume [name=张三, sex=男, age=30, timeArea=1999-2000, company=XX公司]
    Resume [name=张三, sex=男, age=30, timeArea=1999-2000, company=XX公司]

    上面的实现非常简单,如果需要20分简历,就需要实例化20次,如果想把1999改成1998,那么也需要修改20次。

    看到这肯定觉得这样的操作非常笨,只要把不变的信息定义成全局变量,定义一个List集合,利用循环直接实例化20次,每循环一次,把全局变量的信息赋值给新对象,再把新对象放入List集合中,最后List集合里就有了20个相同的简历对象。

    这么做当然和上面的代码产生了相同的效果,但这是真正的复制吗?

    如果已知一个对象有200个成员变量,我们要复制这个对象,那么就需要把这个对象的200个成员变量先取出来,用全局变量存储这200个成员变量的值,然后再创建一个新对象,把全局变量存储的值赋值给新对象的200个成员变量。期间还要小心谨慎,不能赋错了。这样做不是一样的傻么。

    那怎样复制一个对象呢?

    原型模式介绍:http://www.runoob.com/design-pattern/prototype-pattern.html

    简历类实现 Cloneable,重写 clone()

    public class Resume implements Cloneable {
        private String name;
        private String sex;
        private String age;
        private String timeArea;
        private String company;
        
        public Resume(String name) {
            super();
            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("Resume [name=" + name + ", sex=" + sex + ", age=" + age + ", timeArea=" + timeArea + ", company="
                    + company + "]");
        }
        
        public Resume clone() throws CloneNotSupportedException{
            Resume o = (Resume) super.clone();
            return o;
        }
    }

    测试方法

    public class Test {
        public static void main(String[] args) throws CloneNotSupportedException {
            Resume a = new Resume("张三");
            a.setPersonalInfo("男", "30");    
            a.setWorkExperience("1999-2000", "XX公司");
            
            Resume b = a.clone();
            a.display();
            b.display();
        }
    }

    输出结果

    Resume [name=张三, sex=男, age=30, timeArea=1999-2000, company=XX公司]
    Resume [name=张三, sex=男, age=30, timeArea=1999-2000, company=XX公司]

    这样就实现了对象的复制,调用对象的clone()就能复制出一个新的对象。

    克隆相比之前的new对象更快吗?

    每new一次,都需要执行一次构造函数,如果构造函数的执行时间很长,那么多次的执行这个初始化操作就实在是太低效了。一般在初始化的信息不发生变化的情况下,克隆是最好的办法。这既隐藏了对象创建的细节,又对性能是大大对的提高。

    如果复制的对象中包含其他自定义的类,那么这些自定义的类也会被复制吗?

    创建一个地址类

    public class Address {
        private String country;
        private String province;
        
        public Address(String country, String province) {
            super();
            this.country = country;
            this.province = province;
        }
    
        @Override
        public String toString() {
            return "Address [country=" + country + ", province=" + province + "]";
        }
        //省略getter和setter方法   
    }

    在简历类中增加一个地址类成员变量

    public class Resume implements Cloneable {
        private String name;
        private String sex;
        private String age;
        private String timeArea;
        private String company;
        private Address address;
        
        public Resume(String name) {
            super();
            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 Address getAddress() {
            return address;
        }
    
        public void setAddress(Address address) {
            this.address = address;
        }
    
        public void display() {
            System.out.println("Resume [name=" + name + ", sex=" + sex + ", age=" + age + ", timeArea=" + timeArea + ", company="
                    + company + ", address=" + address + "]");
        }
        
        public Resume clone() throws CloneNotSupportedException{
            Resume o = (Resume) super.clone();
            return o;
        }
    }

    测试方法

    public class Test {
        public static void main(String[] args) throws CloneNotSupportedException {
            Address address = new Address("中国", "山东");
            
            Resume a = new Resume("张三");
            a.setPersonalInfo("男", "30");    
            a.setWorkExperience("1999-2000", "XX公司");
            a.setAddress(address);
            
            Resume b = a.clone();
            b.setPersonalInfo("男", "31");    
            a.getAddress().setProvince("江苏");
            b.getAddress().setProvince("湖南");
            
            a.display();
            b.display();
        }
    }

    输出结果

    Resume [name=张三, sex=男, age=30, timeArea=1999-2000, company=XX公司, address=Address [country=中国, province=湖南]]
    Resume [name=张三, sex=男, age=31, timeArea=1999-2000, company=XX公司, address=Address [country=中国, province=湖南]]

    这和我们期望的不同。我们想要简历a的省份是江苏,简历b的省份是湖南,结果却是两份简历的省份都是湖南。

    为什么是这样?

    如果复制的字段能通过他们的内容判断是否相等,那么复制时就会逐位复制。如:基本数据类型和String类。否则只会复制引用但不复制引用的对象。这就叫做“浅复制”,被复制对象的所有变量都含有与原来的对象相同的值,而所有的引用变量都仍然指向原来的对象。

    那如果想把要引用变量所引用的对象也复制,该怎么办?

    这种方式叫做“深复制”。

    让地址类也实现 Cloneable,重写 clone()

    public class Address implements Cloneable{
        private String country;
        private String province;
        
        public Address(String country, String province) {
            super();
            this.country = country;
            this.province = province;
        }
        public Address clone() throws CloneNotSupportedException{
            Address o = (Address) super.clone();
            return o;
        }
        @Override
        public String toString() {
            return "Address [country=" + country + ", province=" + province + "]";
        }
    
        //省略getter和setter方法
    }

    简历类在克隆时也将地址类克隆

    public class Resume implements Cloneable {
        private String name;
        private String sex;
        private String age;
        private String timeArea;
        private String company;
        private Address address;
        
        public Resume(String name) {
            super();
            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 Address getAddress() {
            return address;
        }
    
        public void setAddress(Address address) {
            this.address = address;
        }
    
        public void display() {
            System.out.println("Resume [name=" + name + ", sex=" + sex + ", age=" + age + ", timeArea=" + timeArea + ", company="
                    + company + ", address=" + address + "]");
        }
        
        public Resume clone() throws CloneNotSupportedException{
            Resume o = (Resume) super.clone();
            this.address = this.address.clone();
           return o;
        }
    }

    测试方法

    public class Test {
        public static void main(String[] args) throws CloneNotSupportedException {
            Address address = new Address("中国", "山东");
            
            Resume a = new Resume("张三");
            a.setPersonalInfo("男", "30");    
            a.setWorkExperience("1999-2000", "XX公司");
            a.setAddress(address);
            
            Resume b = a.clone();
            b.setPersonalInfo("男", "31");    
            a.getAddress().setProvince("江苏");
            b.getAddress().setProvince("湖南");
            
            a.display();
            b.display();
        }
    }

    输出结果

    Resume [name=张三, sex=男, age=30, timeArea=1999-2000, company=XX公司, address=Address [country=中国, province=江苏]]
    Resume [name=张三, sex=男, age=31, timeArea=1999-2000, company=XX公司, address=Address [country=中国, province=湖南]]

    这样就实现了复制引用变量时,把引用变量指向的对象也复制一遍。

  • 相关阅读:
    原生js,实现跨越的jsonp
    nodejs+express+jade安装步骤
    浏览器端创建可下载文件
    保留有效数字
    日期转换格式
    js添加千分位
    vue 中的 全选和 反选
    防止域名被恶意解析
    node命令行工具之实现项目工程自动初始化的标准流程
    React router动态加载组件-适配器模式的应用
  • 原文地址:https://www.cnblogs.com/jwen1994/p/10001545.html
Copyright © 2020-2023  润新知