设计模式之原型模式(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());
    }
}

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

目录
打赏
0
0
0
0
22
分享
相关文章
「全网最细 + 实战源码案例」设计模式——原型模式
原型模式(Prototype Pattern)是一种创建型设计模式,通过复制现有对象来创建新对象,适用于创建成本高或复杂的对象场景。其核心思想是“克隆”,避免直接实例化类。结构上分为抽象原型类、具体原型类和客户端。优点包括减少对象创建成本、隐藏复杂性、简化实例创建;缺点是处理循环引用的复杂对象时较为麻烦。实现步骤为定义原型类、重写`clone()`方法并调用。注意事项包括浅拷贝与深拷贝的区别及`Cloneable`接口的使用。
66 20
【Java笔记+踩坑】设计模式——原型模式
对比原型模式和传统方式的实现思路、代码方案、优缺点,阐述原型模式的使用场景,以及深拷贝、浅拷贝等相关概念,并扩展原型模式在Spring源码中的应用。
Java设计模式-原型模式(3)
Java设计模式-原型模式(3)
Java设计模式-原型模式(3)
iLogtail设计模式问题之iLogtail中的原型模式是什么
iLogtail设计模式问题之iLogtail中的原型模式是什么
iLogtail设计模式问题之iLogtail中的原型模式是什么
js设计模式【详解】—— 原型模式
js设计模式【详解】—— 原型模式
79 6
Java设计模式之原型模式详解
Java设计模式之原型模式详解
原型模式-大话设计模式
原型模式-大话设计模式
前端必须掌握的设计模式——模板模式
模板模式(Template Pattern)是一种行为型设计模式,父类定义固定流程和步骤顺序,子类通过继承并重写特定方法实现具体步骤。适用于具有固定结构或流程的场景,如组装汽车、包装礼物等。举例来说,公司年会节目征集时,蜘蛛侠定义了歌曲的四个步骤:前奏、主歌、副歌、结尾。金刚狼和绿巨人根据此模板设计各自的表演内容。通过抽象类定义通用逻辑,子类实现个性化行为,从而减少重复代码。模板模式还支持钩子方法,允许跳过某些步骤,增加灵活性。
217 11
Kotlin教程笔记(51) - 改良设计模式 - 构建者模式
Kotlin教程笔记(51) - 改良设计模式 - 构建者模式
设计模式:工厂方法模式(Factory Method)
工厂方法模式是一种创建型设计模式,通过将对象的创建延迟到子类实现解耦。其核心是抽象工厂声明工厂方法返回抽象产品,具体工厂重写该方法返回具体产品实例。适用于动态扩展产品类型、复杂创建逻辑和框架设计等场景,如日志记录器、数据库连接池等。优点包括符合开闭原则、解耦客户端与具体产品;缺点是可能增加类数量和复杂度。典型应用如Java集合框架、Spring BeanFactory等。

热门文章

最新文章