原型模式与深浅拷贝(克隆)

原型模式简述

先简单的说一下原型模式,原型模式属于创建型模式,和单例模式属于同一个大类,都是用来生成的对象的,与 java 中的 new 不同,原型模式会把一个对象的属性值拷贝一份复制给另外一个对象。而 new 需要传入需要的参数,不如原型模式方便。

示例代码

//需要实现 Cloneable 接口
class Test implements Cloneable{
    public int testId;
    public String testName;
	//需要重写 clone()方法
    @Override
    protected Object clone() throws CloneNotSupportedException {
        // TODO Auto-generated method stub
        return super.clone();
    }

    @Override
    public String toString() {
        return "Test [testId=" + testId + ", testName=" + testName + "]";
    }

    public Test(int testId, String testName) {
        this.testId = testId;
        this.testName = testName;
    }
}
class Main{
    public static void main(String[] args) throws Exception {
        Test test1 = new Test(123456, "zhangsan");
        Test test2 = (Test) test1.clone();
        System.out.println(test2.toString());
    }
}
//输出:Test [testId=123456, testName=zhangsan]

可以看到,输出的 test2 对象确实拿到了 test1 对象的所有属性

浅拷贝与深拷贝

涉及到原型模式,我们常会提起浅拷贝与深拷贝的问题,什么是浅拷贝呢,拿刚才的代码举例子。我们拷贝了一份第一个对象的属性值给第二个对象。这就引申出了一个问题,假如第一个对象里面的参数包含一个对象呢,比如:

class Test implements Cloneable{
    public int testId;
    public String testName;
    public Teacher teacher;
    
    @Override
    protected Object clone() throws CloneNotSupportedException {
        // TODO Auto-generated method stub
        return super.clone();
    }

    public Test(int testId, String testName, Teacher teacher) {
        this.testId = testId;
        this.testName = testName;
        this.teacher = teacher;
    }

    @Override
    public String toString() {
        return "Test [teacher=" + teacher + ", testId=" + testId + ", testName=" + testName + "]";
    }
}

class Teacher implements Cloneable{
    private int teacherId;
    private String teacherName;

    public Teacher(int teacherId, String teacherName) {
        this.teacherId = teacherId;
        this.teacherName = teacherName;
    }

    @Override
    public String toString() {
        return "Teacher [teacherId=" + teacherId + ", teacherName=" + teacherName + "]";
    }
    
}

class Main{
    public static void main(String[] args) throws Exception {
        Teacher teacher = new Teacher(000, "lisi");
        Test test1 = new Test(123456, "zhangsan", teacher);
        Test test2 = (Test) test1.clone();
        System.out.println(test2.toString());
    }
}
//输出为:Test [teacher=Teacher [teacherId=0, teacherName=lisi], 
//testId=123456, testName=zhangsan]

此时我们做一个尝试,我们修改 test1 对象中的 int 型参数 testId 从123456改为777777,我们再次打印两个对象,得到输出:

Test1:
Test [teacher=Teacher [teacherId=0, teacherName=lisi], 
testId=123456, testName=zhangsan]
Test2:
Test [teacher=Teacher [teacherId=0, teacherName=lisi], 
testId=777777, testName=zhangsan]

可以发现确实是实现了我们之前所说的拷贝:两个对象单独拥有相同的属性。
我们换一种方式,再来实验一下:
这里我们修改 test2 中的 Teacher 类型的对象 teacher 中的 teacherId 参数,看看会发生什么,得到输出:

Test1:
Test [teacher=Teacher [teacherId=111, teacherName=lisi], 
testId=123456, testName=zhangsan]
Test2:
Test [teacher=Teacher [teacherId=111, teacherName=lisi], 
testId=123456, testName=zhangsan]

咦?这个时候我们就发现了问题,为什么我修改的是 test2 中的 teacherId 的值,结果影响到了 test1 中的 teacherId 的值,这显然和我想要达到的效果不一样啊。这就是浅拷贝(仅仅是把对象中的参数值拷贝,假如有对象中还有对象的话,那么也会把对象的引用作为值拷贝一份)
那么我们怎么实现我们想要的效果,即拷贝对象间的属性修改互不影响呢?
这里提到一个概念:深拷贝:重写 clone()方法,在对象拷贝的时候,对对象中的对象再进行一次拷贝,重写部分代码如下:

    @Override
    protected Object clone() throws CloneNotSupportedException {
        Object obj = super.clone();
        Test test = (Test)obj;
        this.teacher = (Teacher)test.teacher.clone();
        return obj;
    }

再次进行测试,此时结果如下:

Test1:
Test [teacher=Teacher [teacherId=0, teacherName=lisi], 
testId=123456, testName=zhangsan]
Test2:
Test [teacher=Teacher [teacherId=111, teacherName=lisi], 
testId=123456, testName=zhangsan]

可以观察到达到既定效果。
这就是我们常说的深拷贝与浅拷贝的特定实现,但是需要注意的是,在对象当中拥有多个对象的时候,实现深拷贝需要做的任务量是很大的。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值