• 设计模式之原型模式与深拷贝、浅拷贝


    原型模式

    基本概念

    使用一个已经创建的对象作为原型,通过复制该对象来创建一个新的该类型的对象。Java自带原型模式,通过实现Cloneable接口实现,这种创建对象的方式比new对象的效率更高。

    原型模式通常用来保存对象某一过程中的状态,以实现在必要的时候撤销对对象的更改。

    此方法的缺陷:

    1. 每一个类都需要实现clone()方法,而clone()方法位于类内部,当需要对类代码进行修改时,此方法也需要修改。
    2. 当需要深克隆时,此类中的每一个引用类型对象都需要支持深克隆,实现较麻烦。

    模式的实现

    1. 创建原型类,实现Cloneable接口,并重写clone()方法

      原型类的引用类型属性

      public class Member implements Cloneable{
          private int age;
          private String name;
          private double length;
      
          public Member(int age, String name, double length) {
              this.age = age;
              this.name = name;
              this.length = length;
          }
      
          @Override
          protected Member clone() throws CloneNotSupportedException {
              Member res = (Member) super.clone();
              return res;
          }
      
          public int getAge() {
              return age;
          }
      
          public void setAge(int age) {
              this.age = age;
          }
      
          public String getName() {
              return name;
          }
      
          public void setName(String name) {
              this.name = name;
          }
      
          public double getLength() {
              return length;
          }
      
          public void setLength(double length) {
              this.length = length;
          }
      }
      

      原型类

      public class Collection implements Cloneable {
          private Member member;
          private int id;
      
          public Collection(Member member, int id) {
              this.member = member;
              this.id = id;
          }
      
          @Override
          protected Collection clone() throws CloneNotSupportedException {
              Collection res = (Collection) super.clone();
              //res.setMember(this.getMember().clone());
              return res;
          }
      
          public Member getMember() {
              return member;
          }
      
          public void setMember(Member member) {
              this.member = member;
          }
      
          public int getId() {
              return id;
          }
      
          public void setId(int id) {
              this.id = id;
          }
      }
      
    2. 使用该类的clone()方法实现克隆

      public class ProtoDemo {
          public static void main(String[] args) throws CloneNotSupportedException {
              Member zhangf = new Member(12, "张飞", 12.33);
              Collection coll = new Collection(zhangf, 1);
              Collection coll2 = (Collection) coll.clone();
      
              String str1="collect01	id="+coll.getId()+"	"+coll.getMember()+"	mem="+coll;
              String str2="collect02	id="+coll2.getId()+"	"+coll2.getMember()+"	mem="+coll2;
      
              System.out.println(str1);
              System.out.println(str2);
            
              System.out.println("=============");
              coll.getMember().setName("刘备");
              System.out.println("coll1`s name is "+coll.getMember().getName());
              System.out.println("coll2`s name is "+coll2.getMember().getName());
          }
      }
      

    以上代码实现类浅拷贝,打印结果如下:

    collect01	id=1	cn.sunyog.prototype.Member@e73f9ac	mem=cn.sunyog.prototype.Collection@61064425
    collect02	id=1	cn.sunyog.prototype.Member@e73f9ac	mem=cn.sunyog.prototype.Collection@7b1d7fff
    =============
    coll1`s name is 刘备
    coll2`s name is 刘备
    

    可以看出,当修改了coll对象中membername属性时,coll2对象中对应的次属性也跟着被修改了。如需要实现两个对象互不影响,需要实现深拷贝,即重写Collection类的clone()方法,手动修改它的所有引用类型属性。代码如下:

    @Override
    protected Collection clone() throws CloneNotSupportedException {
        Collection res = (Collection) super.clone();
      	//深拷贝
        res.setMember(this.getMember().clone());
        return res;
    }
    

    以上代码修改后,打印结果如下:

    collect01	id=1	cn.sunyog.prototype.Member@5e2de80c	mem=cn.sunyog.prototype.Collection@1d44bcfa
    collect02	id=1	cn.sunyog.prototype.Member@266474c2	mem=cn.sunyog.prototype.Collection@6f94fa3e
    =============
    coll1`s name is 刘备
    coll2`s name is 张飞
    

    可见两个对象的name属性互不影响,实现了深拷贝

  • 相关阅读:
    01.网页学习阶段、整站分析、规划
    书签搬运
    如何判断两个链表相交及找到第一个相交点
    Windows平台使用git bash管理github中的工程
    二级指针的操作
    结构体的内存对齐
    大端和小端
    剑指Offer——面试题26:复杂链表的复制
    使用editcap命令将ERF格式转换为pcap格式
    如何在STL的map中使用结构体作为键值
  • 原文地址:https://www.cnblogs.com/logic-hatten/p/14451231.html
Copyright © 2020-2023  润新知