创建型模式之原型模式(深拷贝/浅拷贝)

原型模式的定义与特点

原型(Prototype)模式的定义:
用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型相同或相似的新对象。在这里,原型实例指定了要创建的对象的种类。用这种方式创建对象非常高效,根本无须知道对象创建的细节。

原型模式的结构

原型模式包含以下主要角色:
抽象原型类:规定了具体原型对象必须实现的接口。
具体原型类:实现抽象原型类的 clone() 方法,它是可被复制的对象。
访问类:使用具体原型类中的 克隆方法来复制新的对象。

原型模式的实现

原型模式的克隆分为浅克隆深克隆
原型模式通常适用于以下场景:
1.对象之间相同或相似,即只是个别的几个属性不同的时候。
2.对象的创建过程比较麻烦,但复制比较简单的时候。

浅克隆

Java 中的 Object 类提供了浅克隆的 clone() 方法,具体原型类只要实现 Cloneable 接口就可实现对象的浅克隆,这里的 Cloneable 接口就是抽象原型类。其代码如下:

具体原型类:

/**
 * 学生类
 */
@Data
public class Student implements Cloneable {
    private String name;//姓名
    private int age;//年龄
    private ArrayList<String> hobby;//爱好
    /**
     * 浅克隆方法
     * @return
     * @throws CloneNotSupportedException
     */
    @Override
    public Student clone() throws CloneNotSupportedException {
        return (Student)super.clone();
    }
}

浅克隆测试类:

public class StudentTest {
    @Test
    public void test() throws Exception {
        Student student = new Student();
        student.setName("张三");
        student.setAge(18);
        Student student2 = student.clone();
        System.out.println("原型对象:" + student);
        System.out.println("克隆对象:" + student2);
        System.out.println(student == student2);
    }
}

运行结果:
看起来没毛病啊,和我们预期一样,克隆出一模一样内容的对象,而且地址不相同。
其实是有个问题,暂时还没暴露,下边说说浅克隆带来的问题。
在这里插入图片描述

浅克隆带来的问题

注意看,上边的测试代码其实是没有给爱好赋值的。我们来给他加点爱好看看就知道问题在哪了。

测试代码:

public class StudentTest {
    @Test
    public void test() throws Exception {
        Student student = new Student();
        ArrayList<String> hobby = new ArrayList<String>();
        hobby.add("书法");
        hobby.add("画画");
        student.setName("张三");
        student.setAge(18);
        student.setHobby(hobby);//给原型对象添加爱好

        Student student2 = student.clone();
        student2.getHobby().add("看书");//给克隆的对象增加一个爱好

        System.out.println("原型对象:" + student);
        System.out.println("克隆对象:" + student2);
        System.out.println(student == student2);
    }
}

运行结果:
发现问题没?我明明是给克隆出来的对象增加了一个“看书”的爱好,怎么原型对象的爱好也跟着变了呢?这就是浅克隆带来的问题。
下边就轮到深克隆出场来解决这个问题了。
在这里插入图片描述

深克隆

深克隆常见的实现方式有两种:

序列化实现深克隆

具体原型类:
和之前不变,只需实现Serializable接口新增深克隆方法就行。

@Data
public class Student implements Cloneable , Serializable {
    private String name;//姓名
    private int age;//年龄
    private ArrayList<String> hobby;//爱好
    /**
     * 浅克隆方法
     * @return
     * @throws CloneNotSupportedException
     */
    @Override
    public Student clone() throws CloneNotSupportedException {
        return (Student)super.clone();
    }

    /**
     * 序列化深克隆方法
     * @return
     * @throws IOException
     * @throws ClassNotFoundException
     */
    public Student deepClone() throws IOException, ClassNotFoundException {
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream ous = new ObjectOutputStream(bos);
        ous.writeObject(this);

        ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bis);
        return  (Student)ois.readObject();
    }
}

测试代码:

public class StudentTest {
    @Test
    public void test() throws Exception {
        Student student = new Student();
        ArrayList<String> hobby = new ArrayList<String>();
        hobby.add("书法");
        hobby.add("画画");
        student.setName("张三");
        student.setAge(18);
        student.setHobby(hobby);//给原型对象添加爱好

        Student student2 = student.deepClone();//调用深克隆的方法
        student2.getHobby().add("看书");//给克隆的对象增加一个爱好

        System.out.println("原型对象:" + student);
        System.out.println("克隆对象:" + student2);
        System.out.println(student == student2);
    }
}

测试结果:
>

json实现深克隆

具体原型类:

@Data
public class Student implements Cloneable , Serializable {
    private String name;//姓名
    private int age;//年龄
    private ArrayList<String> hobby;//爱好
    /**
     * 浅克隆方法
     * @return
     * @throws CloneNotSupportedException
     */
    @Override
    public Student clone() throws CloneNotSupportedException {
        return (Student)super.clone();
    }
    /**
     * json深克隆方法
     * @return
     */
    public Student jsonDeepClone(){
        String json = JSON.toJSONString(this);
        Student student = JSON.parseObject(json, Student.class);
        return  student;
    }
}

测试结果:也是没毛病的
在这里插入图片描述

原型模式总结

优点:
1.性能优良,Java自带的原型模式是基于内存二进制流的拷贝,比直接new一个对象的性能上提升了很多。
2.可以使用深克隆方式保存对象的状态,使用原型模式将对象复制一份,将其保存起来,简化了创建过程。
缺点:
1.必须要有克隆(或者拷贝)的方法
2.当对已有类进行改造时,需要修改代码,违法开闭原则
注意:
深拷贝和浅拷贝需要运用得当

<<上一篇:单例模式
>>下一篇:工厂方法模式

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值