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());
	}
}

 运行结果:

目前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());
	}

}

运行结果:

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;
    }
}

 改造后运行结果

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

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

 

 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

让程序飞

您的鼓励将是我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值