您当前的位置:首页 > 计算机 > 编程开发 > 设计模式

【设计模式】10.创建型模式-原型模式(Prototype)

时间:02-01来源:作者:点击数:

一、描述:

  将一个对象作为原型,通过对其进行复制而克隆出多个和原型类似的新实例。

二、特点:

  用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型相同或相似的新对象。原型实例指定了要创建的对象的种类。用这种方式创建对象非常高效,根本无须知道对象创建的细节。

三、优点:

  (1)Java自带的原型模式基于内存二进制流的复制,在性能上比直接new一个对象更加优秀。

  (2)可以使用深克隆方式保存对象的状态,使用原型模式将对象复制一份,并将其状态保存起来,简化了创建对象的过程,以便在需要的时候使用(例如恢复到历史某一状态),可辅助实现撤销操作。

四、应用:

  Object的clone方法,实体类实现Cloneable接口类,重写clone()方法,clone方法有浅拷贝和深拷贝两种:

  (1)浅拷贝:只拷贝当前主类的对象,建立一个新的复制对象,但是新的复制对象中的子对象依旧引用之前的主类的子对象地址。(注意:测试clone方法的结果,不能用@Data注解,因为@Data注解重写了hashCode方法,相同属性相同值的情况下,hashCode值一致。)

public class User implements Cloneable {
    private String name;
    private String sex;
    private Integer age;
    private School school;

    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 Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public School getSchool() {
        return school;
    }

    public void setSchool(School school) {
        this.school = school;
    }

    @Override
    protected User clone() throws CloneNotSupportedException {
        return (User) super.clone();
    }

    public static class School implements Cloneable {
        private String name;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        @Override
        protected Object clone() throws CloneNotSupportedException {
            return super.clone();
        }
    }
}

  测试:

@Slf4j
public class MainTest {
    public static void main(String[] args) throws CloneNotSupportedException {
        User user = new User();
        user.setName("张三");
        user.setAge(18);
        User.School school = new User.School();
        school.setName("华师小学");
        user.setSchool(school);

        User user2 = user.clone();
        log.info("user:{}",JSON.toJSONString(user));
        log.info("user2:{}",JSON.toJSONString(user2));
        log.info("user-hashCode:{},user2-hashCode:{},isEquals:{}", user.hashCode(), user2.hashCode(), user.hashCode() == user2.hashCode());
        log.info("user-school-hashCode:{},user2-school-hashCode:{}, isEquals:{}", user.getSchool().hashCode(), user2.getSchool().hashCode(), user.getSchool().hashCode() == user2.getSchool().hashCode());
    }
}

  运行结果:

user:{"age":18,"name":"张三","school":{"name":"华师小学"}}

user2:{"age":18,"name":"张三","school":{"name":"华师小学"}}

user-hashCode:662736689,user2-hashCode:1320677379,isEquals:false

user-school-hashCode:852687460,user2-school-hashCode:852687460, isEquals:true

  从结果可以看出来,主对象在克隆之后,hashCode值变化,说明为克隆主对象又重新开辟了内存存储。但是克隆子对象school的hashCode值仍然为原来的hashCode,说明克隆后的user2对象中的school仍然引用的user的school对象地址。这就是浅拷贝。

  浅拷贝的util方法有:

BeanUtil.copyProperties(user, user2);

  (2)深拷贝:比浅拷贝更进一步,子对象也都重新开辟了新的内存存储,重写clone方法:

/**
 * User
 *
 * @author zhouxy
 * @date 2022/5/24
 **/
public class User implements Cloneable {
    private String name;
    private String sex;
    private Integer age;
    private School school;

    //getter、setter方法
  ......

    @Override
    protected User clone() throws CloneNotSupportedException {
        User copyUser = (User) super.clone();
    //重写school的clone方法
        School school = copyUser.getSchool().clone();
        copyUser.setSchool(school);
        return copyUser;
    }

    public static class School implements Cloneable {
        private String name;

     //getter、setter方法
        .....

        @Override
        protected School clone() throws CloneNotSupportedException {
            return (School) super.clone();
        }
    }
}

  测试代码仍然和浅拷贝的测试代码一致,直接显示测试结果:

user:{"age":18,"name":"张三","school":{"name":"华师小学"}}
user2:{"age":18,"name":"张三","school":{"name":"华师小学"}}
user-hashCode:662736689,user2-hashCode:1320677379,isEquals:false
user-school-hashCode:852687460,user2-school-hashCode:246399377, isEquals:false

  school的对象的hashCode也发生了变化。

方便获取更多学习、工作、生活信息请关注本站微信公众号城东书院 微信服务号城东书院 微信订阅号
推荐内容
相关内容
栏目更新
栏目热门