Java设计模式-原型(prototype)模式详解(深克隆,浅克隆)

1.简单介绍

  1. 通过new产生一个对象需要非常繁琐的数据准备,或者访问权限,则可以使用原型模式;
  2. 主要运用Java的克隆技术,以某个对象为原型,复制新对象;
  3. 克隆创建对象,类似于new,新创建的对象属性采用默认值,但是克隆出来的对象属性值完全和原型对象相同,而且克隆出的新对象改变不会影响原型对象,这样就只需要对克隆模型进行修改就可以了;
  4. 原型模型的实现:Cloneable接口和clone方法;
  5. 如果对象使用new创建的时候比较复杂,就可以直接使用克隆创建对象;

2. 浅克隆

克隆的对象:

//这里实现浅克隆,原型模式需要克隆,
public class Computer implements Cloneable {
   private String brand;
   private BuyDate buytime;

   public Computer(String brand, BuyDate buytime) {
       this.brand = brand;
       this.buytime = buytime;
   }

   public BuyDate getBuytime() {
       return buytime;
   }

   public void setBuytime(BuyDate buytime) {
       this.buytime = buytime;
   }

   //这里定义一个创建方法;
   public String getBrand() {
       return brand;
   }
   //这里只定义一个get方法,因为我也只取一个值;
   public void setBrand(String brand) {
       this.brand = brand;
   }

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

class BuyDate{
   private String time;

   public BuyDate(String time) {
       this.time = time;
   }

   public String getTime() {
       return time;
   }

   public void setTime(String time) {
       this.time = time;
   }

   @Override
   public String toString() {
       return "BuyDate{" +
               "time='" + time + '\'' +
               '}';
  }
}

测试类:

class Test{
    public static void main(String[] args) {
       BuyDate b = new BuyDate("2020");
        try {
            //创建对象;
            Computer com = new Computer("联想",b );
            //克隆对象,本来返回一个Object,但是后面需要用到Computer类中的方法,所以将其转换为这个;
            Computer clone = (Computer) com.clone();
            //对对象值进行修改;看克隆到的值是什么;
            com.setBrand("华硕");
            //这里直接对对象地址进行修改;
            com.getBuytime().setTime("2017");
            System.out.println(com.getBrand());

            System.out.println("原始对象的商标:"+com.getBrand());
            System.out.println(com.getBuytime());
            System.out.println("拷贝对象的商标:"+clone.getBrand());
            System.out.println(clone.getBuytime());
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }

    }
}	

测试结果:
从上面的结果可以看出来,这个浅克隆,在使用的时候调用的对象地址还是一样的;因为修改克隆后的BuyDate之后,原对象的也被修改了;就类似于下图;也就是说它们指向的地址是一样的,无论谁对其中的值进行修改,两个对象取到的值都会被改掉;

这里可能有人会对那个String类型的Brand为什么没有变化保持疑问,我一开始也没想到,后面仔细一想,String这个是没法改的,它的底层是一个final类型的数组,所以每次修改其实都是重新创建,重新创建地址自然就不一样了,这样想就知道为什么两个类型会不一致了;

3.深克隆

//这里实现浅克隆,原型模式需要克隆,
public class Computer implements Cloneable {
    private String brand;
    private BuyDate buytime;

    public Computer(String brand, BuyDate buytime) {
        this.brand = brand;
        this.buytime = buytime;
    }

    public BuyDate getBuytime() {
        return buytime;
    }

    public void setBuytime(BuyDate buytime) {
        this.buytime = buytime;
    }

    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        Computer computer = (Computer) super.clone();
        //在赋值的时候强转一下就可以了,右边其实是BuyDate类型;
        computer.buytime=(BuyDate) this.buytime.clone();
        return computer;
    }
}

//想要这个对象属性能够克隆,必须要实现Cloneable接口;和clone方法;
class BuyDate implements Cloneable{
    private String time;

    public BuyDate(String time) {
        this.time = time;
    }

    public String getTime() {
        return time;
    }

    public void setTime(String time) {
        this.time = time;
    }

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

    @Override
    public String toString() {
        return "BuyDate{" +
                "time='" + time + '\'' +
                '}';
    }
}

这里需要注意的点,就是,如果需要将某些属性进行深克隆,这些属性如果是某些类的对象,那么就需要将这些类实现Cloneable接口,同时还要实现Object的clone的方法;最重要的是需要对什么属性进行深克隆,那么那个属性就要在重写克隆方法里面重新调用一下;

这里的测试类使用的就是上次的一样的测试类;
测试结果:

使用序列化和反序列化也可以实现深克隆;

猜你喜欢

转载自blog.csdn.net/dxsdcyy/article/details/107135452