天天看点

GoF设计模式(五) - 原型模式(浅复制与深复制)

前言

原型模式(Prototype Pattern)是用于创建重复的对象,同时又能保证性能,通俗来讲就是从一个对象再创建另外一个可定制的对象,而且不需知道任何创建的细节,

这种模式是实现了一个原型接口,该接口用于创建当前对象的克隆。当直接创建对象的代价比较大时,则采用这种模式。 

1. 浅复制

  创建Student对象实现Cloneable接口重写clone()方法

@ToString
public class Student implements Cloneable{
    //姓名
    private String name;
    //性别
    private String sex;
  
    public void setStudentInfo(String name,String sex){
        this.name = name;
        this.sex = sex;
    }

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

 测试类:

@SpringBootTest
class PrototypeDemoApplicationTests {

	@Test
	void contextLoads() throws CloneNotSupportedException {
		Student student = new Student();
		student.setStudentInfo("张三","男");

		Student cloneStudent = (Student)student.clone();
		cloneStudent.setStudentInfo("李四","男");

		System.out.println(student.toString());
		System.out.println(cloneStudent.toString());
	}
}
           

 运行结果:

GoF设计模式(五) - 原型模式(浅复制与深复制)

目前Student对象中都是String类型,而string是一种拥有值类型特点的特殊引用类型,重写了clone()后,当字段是值类型的,则会对该字段执行逐位复制,如果是引用类型则不会被克隆过来。

以示例说话

新增一个Address对象

@Data
public class Address {
    //省份
    private String province;
    //市
    private String city;
    //区
    private String area;
    //街道
    private String street;
}
           

Student对象改造

@ToString
public class Student implements Cloneable{
    //姓名
    private String name;
    //性别
    private String sex;
    //地址
    private Address address = new Address();

    public void setStudentInfo(String name,String sex){
        this.name = name;
        this.sex = sex;
    }

    public void setAddressInfo(String province, String city, String area, String street){
        address.setProvince(province);
        address.setCity(city);
        address.setArea(area);
        address.setStreet(street);
    }


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

 测试类:

@SpringBootTest
class PrototypeDemoApplicationTests {

	@Test
	void contextLoads1() throws CloneNotSupportedException {
		Student student = new Student();
		student.setStudentInfo("张三","男");
		student.setAddressInfo("浙江省","杭州市","西湖区","xx街道");

		Student cloneStudent = (Student)student.clone();
		cloneStudent.setStudentInfo("李四","男");
		student.setAddressInfo("湖南省","长沙市","岳麓区","xx街道");


		System.out.println(student.toString());
		System.out.println(cloneStudent.toString());
	}

}
           

运行结果:

GoF设计模式(五) - 原型模式(浅复制与深复制)

Object类提供的clone()方法只是拷贝本对象,对象内部的数组、引用对象等都不拷贝,还是指向原生对象的内部元素地址,这种拷贝就叫做浅拷贝。这种方式非常不安全,任何一个拷贝对象改变了私有变量的值,其他所有对象的变量的值都会随着改变。

2. 深复制

由于浅复制是有风险的 针对如上做出改动

Address对象改造 也实现Cloneable接口

@Data
public class Address implements Cloneable{
    //省份
    private String province;
    //市
    private String city;
    //区
    private String area;
    //街道
    private String street;

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

Student对象改造

@ToString
public class Student implements Cloneable{
    //姓名
    private String name;
    //性别
    private String sex;
    //地址
    private Address address = new Address();

    public void setStudentInfo(String name,String sex){
        this.name = name;
        this.sex = sex;
    }

    public void setAddressInfo(String province, String city, String area, String street){
        address.setProvince(province);
        address.setCity(city);
        address.setArea(area);
        address.setStreet(street);
    }


    @Override
    public Object clone() throws CloneNotSupportedException{
        Student student = (Student) super.clone();
        student.address = (Address) this.address.clone();
        return student;
    }
}
           

 改造后运行结果

GoF设计模式(五) - 原型模式(浅复制与深复制)

这样就实现了完全的拷贝,两个对象之间没有任何瓜葛,你改你的,我改我的,互不影响,这种拷贝就叫做深复制。

源码: https://download.csdn.net/download/javanbme/17853753

继续阅读