设计模式-原型模式

原型模式

1.本质

对已经存在的对象模型进行拷贝

  • 应用场景

类初始化消耗资源较多的情况下
new对象非常繁琐的过程
构造函数复杂
循环体中产生大量对象时??

2.分类:
2.1浅克隆
  • 特点

拷贝的是对象的引用,而不是对象的值。如果克隆的对象发生了变化,原对象也会发生改变,对代码存在风险

  • 实现

JDK提供了Cloneable接口,用户只需要实现这个接口,重写Object类的clone方法,然后执行super.clone() 就可以拷贝对象了。注意的是,Object类的clone方法是native方法

2.2深克隆
  • 特点

拷贝的是对象的值,而不是引用。拷贝对象和原对象没有任何关系。如果原对象中有一个引用类型的属性,拷贝之后,这个引用类型的属性发生了变化,不会影响到原对象的引用类型属性的值。

  • 实现

方式1: 对原对象,实现Serializable接口,利用对象的序列化和反序列化来完成对象的拷贝(参考单例模式中的序列化破坏单例的举例)
方式2:通过json实现克隆
这两种方式拷贝,都不需要实现Cloneable接口

  • 注意点

克隆可能会破坏单例,需要在代码中规避这种风险,如果是单例,就不要实现Cloneable接口。
JDK中,凡是实现了Cloneable接口的clone方法,都是浅克隆,深克隆需要自行实现

3.浅克隆举例
package com.gupaoedu.vip.pattern.prototype.shallowclone;

import lombok.Data;
import lombok.ToString;
import java.util.List;

/**
 * 浅克隆: 实现Cloneable接口,重写clone方法
 */
@Data
@ToString
public class ConcretePrototype implements Cloneable {
    private int age;
    private String name;
    private List<String> hobbies;

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

测试类:在克隆出对象后,修改克隆对象的hobbies属性,然后再去对比原对象的hobbies:

package com.gupaoedu.vip.pattern.prototype.shallowclone;

import java.util.ArrayList;

public class ShallowCloneTest {
    public static void main(String[] args) throws CloneNotSupportedException {
        ConcretePrototype prototype = new ConcretePrototype();
        prototype.setAge(18);
        prototype.setName("jack");

        ArrayList<String> hobbies = new ArrayList<>();
        hobbies.add("reading");
        prototype.setHobbies(hobbies);
        System.out.println("源原对象:" + prototype);

        ConcretePrototype copy = (ConcretePrototype) prototype.clone();
        // 克隆完成后,给克隆对象添加特有的属性
        copy.getHobbies().add("swimming");
        System.out.println("克隆对象:" + copy);
        System.out.println("修改克隆对象后,源对象:" + prototype);
        System.out.println("prototype == copy? " + (prototype == copy));
        System.out.println("prototype.hobbies == copy.hobbies ? " + (prototype.getHobbies() == copy.getHobbies()));
    }
}

测试结果
在这里插入图片描述
我们仅仅期望修改一下克隆出来的对象的属性,结果却把原对象的hobbies属性也修改了,这就是浅克隆的体现,并且prototype.hobbies == copy.hobbies 结果为true,说明拷贝的是hobbies的地址,而不是hobbies这个list的内容。因此,浅拷贝其实仅仅是复制了对象的引用地址,并不是真正的复制了对象的属性。

4. 深克隆举例
package com.gupaoedu.vip.pattern.prototype.deepclone;

import lombok.Data;
import lombok.ToString;

import java.io.*;
import java.util.List;

@Data
@ToString
public class ConcretePrototype  implements Serializable {
    private int age;
    private String name;
    private List<String> hobbies;

    public ConcretePrototype deepClone(){
        try {
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(bos);
            oos.writeObject(this);

            ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(bis);
            ConcretePrototype clone =(ConcretePrototype) ois.readObject();
            return clone;
        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }
}
package com.gupaoedu.vip.pattern.prototype.deepclone;

import java.util.ArrayList;

public class DeepCloneTest {
    public static void main(String[] args) {
        ConcretePrototype prototype = new ConcretePrototype();
        prototype.setAge(18);
        prototype.setName("jack");
        ArrayList<String> hobbies = new ArrayList<>();
        hobbies.add("reading");
        prototype.setHobbies(hobbies);
        System.out.println("原对象:" + prototype);


        ConcretePrototype copy = prototype.deepClone();
        // 克隆完成后,给克隆对象添加特有的属性
        copy.getHobbies().add("swimming");
        System.out.println("克隆对象:" + copy);
        System.out.println("修改克隆对象后,原对象:" + prototype);
        System.out.println("prototype == copy? " + (prototype == copy));
        System.out.println("prototype.hobbies == copy.hobbies ? " + (prototype.getHobbies() == copy.getHobbies()));
    }
}

测试结果:
在这里插入图片描述
说明,对于原对象中的引用类型数据,拷贝的不再是引用的地址,因此克隆对象的改变,不会改变原来的对象。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值