Java 基于 Cloneable 接口实现原型模式(浅拷贝与深拷贝)

目录

前言

UML

plantuml

类图

实战代码

浅拷贝

深拷贝


前言

在业务开发中,有时需要对业务对象进行一次复制,得到一个一模一样的副本。最直观的做法就是重新 new 一个对象,然后将原型对象的值依次设置到克隆对象中,但是这样写代码过于冗余,也不高效。

设计模式中的原型模式便可以很好的解决这个问题,Java 已经内置了抽象原型接口 Cloneable,只需要实现该接口,便能够通过 clone 方法快速复制一个克隆的对象,应当注意的是,clone 是浅拷贝,如果类中存在引用对象属性,则原型对象和克隆对象的该属性会指向同一个对象引用。

实现深拷贝,有两种方式

  1. 在调用 super.clone() 后,再依次调用引用对象属性的 clone 方法
  2. 使用序列化实现

UML

plantuml

@startuml
'https://plantuml.com/class-diagram

interface Cloneable {
    + clone() : type
}

class Item {
    - field : type
    + clone() : Item
}

class Client {
    + {static} main(String[]) : void
}

Cloneable <|.. Item

Client ..> Item

@enduml

类图

实战代码

浅拷贝

public class Item implements Cloneable, Serializable {
    private int a;
    private float b;
    private double c;
    private String d;

    public Item(int a, float b, double c, String d){
        this.a = a;
        this.b = b;
        this.c = c;
        this.d = d;
    }

    public int getA() {
        return a;
    }

    public void setA(int a) {
        this.a = a;
    }

    public float getB() {
        return b;
    }

    public void setB(float b) {
        this.b = b;
    }

    public double getC() {
        return c;
    }

    public void setC(double c) {
        this.c = c;
    }

    public String getD() {
        return d;
    }

    public void setD(String d) {
        this.d = d;
    }

    @Override
    public String toString() {
        return "Item{" +
                "a=" + a +
                ", b=" + b +
                ", c=" + c +
                ", d='" + d + '\'' +
                '}';
    }

    @Override
    protected Item clone() {
        Item item = null;
        try {
            item = (Item)super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return item;
    }

}

深拷贝

public class RefItem implements Cloneable, Serializable {
    Item item;

    public RefItem(Item item) {
        this.item = item;
    }

    public Item getItem() {
        return item;
    }

    public void setItem(Item item) {
        this.item = item;
    }

    @Override
    public String toString() {
        return "RefItem{" +
                "item=" + item +
                '}';
    }

    /**
     * 层层递进调用clone方法
     * */
    @Override
    protected RefItem clone() {
        RefItem refItem = null;
        try {
            refItem = (RefItem)super.clone();
            refItem.item = refItem.item.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return refItem;
    }

    /**
     * 通过实现Serializable接口
     * */
    public static <T extends Serializable> T clone(T obj) {
        T cloneObj = null;
        try {
            // 写入字节流
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            ObjectOutputStream obs = new ObjectOutputStream(out);
            obs.writeObject(obj);
            obs.close();

            // 写入原始对象,生成新对象
            ByteArrayInputStream ios = new ByteArrayInputStream(out.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(ios);
            // 返回生成的新对象
            cloneObj = (T) ois.readObject();
            ois.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return cloneObj;
    }

}

在 spring 项目中,可直接使用 spring 框架的工具类,将代码简化


    /**
     * 通过实现Serializable接口
     * */
    public static <T extends Serializable> T clone(T obj) {
        return (T) SerializationUtils.deserialize(SerializationUtils.serialize(obj));
    }

  • 15
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值