设计模式之原型模式(Cloneable接口、浅拷贝、深拷贝)

简介: 设计模式之原型模式(Cloneable接口、浅拷贝、深拷贝)

原型模式是23种设计模式之一,很多类的拷贝都使用到了此模式。

例如Spring框架中bean的作用域prototype模式。

意义:当我们想要去复制一个对象的时候,使用原型模式,就可以无需知道该对象的内部细,快速高效的去拷贝出一个对象。

类型:创建型模式

未使用原型模式

场景:构建一个细胞类,然后创建一个红细胞,复制该红细胞

//1.细胞类
public class Cell {
    /**
     * 属性:细胞名称
     * 这里属性目前只有一个方便编写、实际这里属性越多,越能体现原型模式重要性
     */
    private String name;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Cell() {
    }
    public Cell(String name) {
        this.name = name;
    }
}
public class Test {
    public static void main(String[] args) {
        //先创建一个细胞对象
        Cell cell = new Cell();
        cell.setName("红细胞");
        //根据上面创建的在复制一个红细胞
        Cell cell1 = new Cell(cell.getName());
        //比较是相同的红细胞吗,,结果是false
        System.out.println(cell == cell1);
    }
}

到这里小伙伴肯定有个疑惑,直接new不行吗,在这里确实直接new很方便,但是实际工作中,一个对象往往有几十个属性,那么在一个个填充就会非常麻烦,假如说对象嵌套,那更会麻烦,接下来我们用原型模式构建。

使用原型模式

原型模式实现思路:类本身实现Cloneable接口,该接口是Object类的方法。

在拷贝对象的时候直接调用clone()方法就可以了,但是要注意该方法返回值为Object,需要进行强制类型转换。

//1.细胞类
public class Cell implements Cloneable {
    /**
     * 属性:细胞名称
     * 这里属性目前只有一个方便编写、实际这里属性越多,越能体现原型模式重要性
     */
    private String name;
    /**
     *  这里我们实现clone接口,默认使用父类的实现方式
     */
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Cell() {
    }
    public Cell(String name) {
        this.name = name;
    }
}
public class Test {
    public static void main(String[] args) throws CloneNotSupportedException {
        //先创建一个细胞对象
        Cell cell = new Cell();
        cell.setName("红细胞");
        //直接使用clone方法克隆对象
        Cell cell1 = (Cell)cell.clone();
        //结果为:
        //红细胞
        //false
        System.out.println(cell1.getName());
        System.out.println(cell == cell1);
    }
}

浅拷贝和深拷贝

到这里,原型模式已经学习完了。那么你肯定有一种感觉,这么简单。其实使用clone接口的父类方法只是一种浅拷贝,那么浅拷贝是什么呢?

浅拷贝其实把我们对象中的基本数据类型和String类型进行了拷贝,如果是对象类型,那么直接把内存地址进行拷贝,实际上还是原来的对象。

我们来测试一下clone是否是浅拷贝?

//1.细胞类
public class Cell implements Cloneable {
    private String name;
    //这里又添加了一个细胞对象细胞中含有细胞
    private Cell cell;
    /**
     *  这里我们实现clone接口,默认使用父类的实现方式
     */
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Cell getCell() {
        return cell;
    }
    public void setCell(Cell cell) {
        this.cell = cell;
    }
    public Cell() {
    }
    public Cell(String name, Cell cell) {
        this.name = name;
        this.cell = cell;
    }
    public Cell(String name) {
        this.name = name;
    }
}
public class Test {
    public static void main(String[] args) throws CloneNotSupportedException {
        //先创建一个细胞对象
        Cell cell = new Cell("卵细胞",new Cell("精子"));
        //直接使用clone方法克隆对象
        Cell cell1 = (Cell)cell.clone();
        //结果为true
        System.out.println(cell.getCell() == cell1.getCell());
    }
}

发现结果为true,果然是同一个精子,也就是两个不同的卵细胞用了同一个精子,这不麻烦了吗。

那么如何实现深拷贝呢?

首先我们了解什么是深拷贝:深拷贝其实就是在对象拷贝过程中,如果有引用类型的属性,那么也会重新创建一个新的对象。

而实现深拷贝,其实我们修改clone接口就可以了。

自定义clone接口

//1.细胞类
public class Cell implements Cloneable {
    private String name;
    //这里又添加了一个细胞对象细胞中含有细胞
    private Cell cell;
    /**
     * 这里我们实现clone接口,默认使用父类的实现方式
     */
    @Override
    protected Object clone() throws CloneNotSupportedException {
        Cell clone = (Cell) super.clone();
        if (this.cell != null){
            clone.setCell((Cell) this.cell.clone());
        }
        return clone;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Cell getCell() {
        return cell;
    }
    public void setCell(Cell cell) {
        this.cell = cell;
    }
    public Cell() {
    }
    public Cell(String name, Cell cell) {
        this.name = name;
        this.cell = cell;
    }
    public Cell(String name) {
        this.name = name;
    }
}
public class Test {
    public static void main(String[] args) throws CloneNotSupportedException {
        //先创建一个细胞对象
        Cell cell = new Cell("卵细胞",new Cell("精子"));
        //直接使用clone方法克隆对象
        Cell cell1 = (Cell)cell.clone();
        //结果为false
        System.out.println(cell.getCell() == cell1.getCell());
    }
}

最终实现了深拷贝,但是这种方式编码比较复杂,这里一个属性还行,但是二三十个属性后就很吃力了。

序列化

其实序列化可以实现深拷贝

//1.细胞类
public class Cell implements Serializable {
    private String name;
    //这里又添加了一个细胞对象细胞中含有细胞
    private Cell cell;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Cell getCell() {
        return cell;
    }
    public void setCell(Cell cell) {
        this.cell = cell;
    }
    public Cell() {
    }
    public Cell(String name, Cell cell) {
        this.name = name;
        this.cell = cell;
    }
    public Cell(String name) {
        this.name = name;
    }
}
public class Test {
    public static void main(String[] args) throws CloneNotSupportedException, IOException, ClassNotFoundException {
        //先创建一个细胞对象
        Cell cell = new Cell("卵细胞",new Cell("精子"));
        //把对象进行序列化输出
        ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
        ObjectOutputStream out = new ObjectOutputStream(byteOut);
        out.writeObject(cell);
        //把输出的对像进行反序列化
        ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray());
        ObjectInputStream in = new ObjectInputStream(byteIn);
        Cell cell1 = (Cell) in.readObject();
        //false
        System.out.println(cell.getCell().getName());
        System.out.println(cell1.getCell().getName());
        System.out.println(cell.getCell() == cell1.getCell());
    }
}

实际操作中,我们只需要把序列化和反序列化抽出一个工具类就可以反复调用了。

相关文章
|
2月前
|
设计模式 Java 关系型数据库
【Java笔记+踩坑】设计模式——原型模式
对比原型模式和传统方式的实现思路、代码方案、优缺点,阐述原型模式的使用场景,以及深拷贝、浅拷贝等相关概念,并扩展原型模式在Spring源码中的应用。
【Java笔记+踩坑】设计模式——原型模式
|
2月前
|
设计模式 Java
Java设计模式-原型模式(3)
Java设计模式-原型模式(3)
Java设计模式-原型模式(3)
|
4月前
|
设计模式
iLogtail设计模式问题之iLogtail中的原型模式是什么
iLogtail设计模式问题之iLogtail中的原型模式是什么
iLogtail设计模式问题之iLogtail中的原型模式是什么
|
4月前
|
设计模式 JavaScript
js设计模式【详解】—— 原型模式
js设计模式【详解】—— 原型模式
50 6
|
5月前
|
设计模式 Java
Java设计模式之原型模式详解
Java设计模式之原型模式详解
|
5月前
|
设计模式
原型模式-大话设计模式
原型模式-大话设计模式
|
5月前
|
设计模式
设计模式六大原则之 接口分离原则
设计模式六大原则之 接口分离原则
|
5月前
|
设计模式 Java Spring
设计模式——原型模式
设计模式——原型模式
|
17天前
|
设计模式 安全 Java
Kotlin教程笔记(51) - 改良设计模式 - 构建者模式
Kotlin教程笔记(51) - 改良设计模式 - 构建者模式
|
2月前
|
设计模式 数据库连接 PHP
PHP中的设计模式:提升代码的可维护性与扩展性在软件开发过程中,设计模式是开发者们经常用到的工具之一。它们提供了经过验证的解决方案,可以帮助我们解决常见的软件设计问题。本文将介绍PHP中常用的设计模式,以及如何利用这些模式来提高代码的可维护性和扩展性。我们将从基础的设计模式入手,逐步深入到更复杂的应用场景。通过实际案例分析,读者可以更好地理解如何在PHP开发中应用这些设计模式,从而写出更加高效、灵活和易于维护的代码。
本文探讨了PHP中常用的设计模式及其在实际项目中的应用。内容涵盖设计模式的基本概念、分类和具体使用场景,重点介绍了单例模式、工厂模式和观察者模式等常见模式。通过具体的代码示例,展示了如何在PHP项目中有效利用设计模式来提升代码的可维护性和扩展性。文章还讨论了设计模式的选择原则和注意事项,帮助开发者在不同情境下做出最佳决策。