深度学习设计模式之原型模式


前言

本文主要学习原型模式,原型模式是一种创建对象的模式,原型实例指定创建对象的种类,通过拷贝的方式创建新的对象。


一、介绍

原型模式,是一种对象创建型模式,使用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象,主要用于创建重复的对象同时又要求性能的情况。

二、详细分析

1.核心组成

  • Prototype: 声明克隆方法的接口,是所有具体原型类的公共父类,Cloneable接口,Serializable接口;
  • ConcretePrototype : 具体原型类;
  • Client: 调用一个原型对象克隆自身从而创建一个新的对象。

浅拷贝

实现cloneable接口,只能拷贝基本数据类型对象
在这里插入图片描述

深拷贝

实现Serializable接口,自定义deepClone方法,通过二进制输入输出实现深拷贝;
在这里插入图片描述

2.实现步骤

  1. 创建具体原型类;
  2. 如果浅拷贝(只能拷贝基本类型)则实现cloneable接口,重写clone方法;如果是深拷贝(除了基本类型,还有引用类型)则实现Serializable接口,自定义序列化方法。
  3. 客户端调用;

3.代码示例

浅拷贝

具体原型类,实现cloneable接口,重写clone方法:


/**
 * 具体原型类
 */
public class Student implements Cloneable {

    /**
     * 名字
     */
    private String name;

    /**
     * 年龄
     */
    private int age;

    public Student(){
        System.out.println("创建学生类");
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    /**
     * 实现 Cloneable colone 方法
     * @return
     * @throws CloneNotSupportedException
     */
    @Override
    protected Student clone() throws CloneNotSupportedException {
        return (Student) super.clone();
    }

}

客户端:

/**
 * 客户端
 */
public class Client {

    public static void main(String[] args) throws CloneNotSupportedException {
        Student student = new Student();
        student.setAge(18);
        student.setName("王小明");

        Student clone = student.clone();
        clone.setName("韩美美");

        System.out.println(student.toString());
        System.out.println(clone.toString());

    }

}

结果:
在这里插入图片描述
通过输出结果,可以发现初始化的构造方法只调用了1次。
浅拷贝存在一个问题,就是只能拷贝基本数据类型,如果使用了引用数据类型,比如集合,或者对象的时候,拷贝将出现问题,如下:
新增加课程集合:

public class Student implements Cloneable {

    /**
     * 名字
     */
    private String name;

    /**
     * 年龄
     */
    private int age;

    /**
     * 课程
     */
    private List<String> clazz = new ArrayList<>();

    public Student(){
        System.out.println("创建学生类");
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public List<String> getClazz() {
        return clazz;
    }

    public void setClazz(List<String> clazz) {
        this.clazz = clazz;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", clazz=" + clazz +
                '}';
    }
    /**
     * 实现 Cloneable colone 方法
     * @return
     * @throws CloneNotSupportedException
     */
    @Override
    protected Student clone() throws CloneNotSupportedException {
        return (Student) super.clone();
    }

}

客户端:

public class Client {

    public static void main(String[] args) throws CloneNotSupportedException {
        Student student = new Student();
        student.setAge(18);
        student.setName("王小明");
        student.getClazz().add("语文");

        Student clone = student.clone();
        clone.setName("韩美美");
        clone.getClazz().add("数学");

        System.out.println(student.toString());
        System.out.println(clone.toString());

    }

}

结果:
在这里插入图片描述
发现被克隆的对象的clazz列表也发生了变化,所以得出以下结论:
如果原型对象的成员变量是基本数据类型(int、double、byte、boolean、char等),将复制一份给克隆对象;如果原型对象的成员变量是引用类型,则将引用对象的地址复制一份给克隆对象,也就是说原型对象和克隆对象的成员变量指向相同的内存地址。

深拷贝

实现Serializable接口,使用二进制输入输出实现:
具体原型类:

/**
 * 具体原型类
 */
public class Student implements Cloneable,Serializable {

    /**
     * 名字
     */
    private String name;

    /**
     * 年龄
     */
    private int age;

    /**
     * 课程
     */
    private List<String> clazz=new ArrayList<>();

    public Student(){
        System.out.println("创建学生类");
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public List<String> getClazz() {
        return clazz;
    }

    public void setClazz(List<String> clazz) {
        this.clazz = clazz;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", clazz=" + clazz +
                '}';
    }
    /**
     * 实现 Cloneable colone 方法
     * @return
     * @throws CloneNotSupportedException
     */
    @Override
    protected Student clone() throws CloneNotSupportedException {
        return (Student) super.clone();
    }


    /**
     * 深拷贝
     * @return
     */
    protected Object deepClone(){
        try{
            // 输出 序列化
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
            objectOutputStream.writeObject(this);

            // 输入 序列化
            ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
            ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
            return objectInputStream.readObject();
        }catch (Exception e){
            e.printStackTrace();
        }

        return null;
    }

}

客户端:

    public static void main(String[] args) throws CloneNotSupportedException {
        Student student = new Student();
        student.setAge(18);
        student.setName("王小明");
        student.getClazz().add("语文");

        Student clone = (Student) student.deepClone();
        clone.setName("韩美美");
        clone.getClazz().add("数学");

        System.out.println(student.toString());
        System.out.println(clone.toString());

    }

结果:
在这里插入图片描述
可以看到已经解决了 浅拷贝引用类型,拷贝的问题,得出结论:
无论原型对象的成员变量是基本数据类型还是引用类型,都将复制一份给克隆隆对象。

4.优缺点

优点

  • 当创建新的对象实例较为复杂时,使用原型模式可以简化对象的创建过程,可以提高新实例的创建效率;
  • 可以使用深拷贝,记录保存当前的状态,随时可恢复历史。

缺点

  • 需要为每一个类都配备一个克隆方法,对已有的类进行改造,需要修改源码,不符合开闭原则;
  • 深拷贝实现比较复杂,当对象之间存在多重的嵌套引用时,需要对每一层对象对应的类都必须支持深克隆。

5.使用场景

  • 创建的对象过于庞大的时候,可以通过拷贝对已有的对象进行拷贝,提高效率;
  • 如果系统要保存对象的状态,做备用的时候可以使用拷贝,留存。

总结

以上就是今天要讲的内容,本文介绍了原型模式的组成,实现和使用场景,并提供代码示例。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值