原型模式-克隆一个对象

文章介绍了Java编程中使用原型模式来减少重复代码,通过接口Prototype定义克隆方法。具体原型类Button实现了克隆功能,展示了如何进行浅克隆和深克隆。浅克隆复制对象及其值类型成员,而引用类型成员共享同一引用。深克隆则对所有成员变量进行复制,包括引用类型。此外,文章还提到了原型管理器的概念,用于存储和复制多个原型对象。
摘要由CSDN通过智能技术生成

 在开发一个界面的时候,里面有多个Button,这些对象的属性内容相似。如果一个个实例化Button对象,并设置其属性,那么代码量将会增多。

通过一个原型对象克隆出多个一模一样的对象,该模式被称为原型模式。

 图 原型模式

Prototype: 抽象原型类,是声名克隆方法的接口,也可以是具体原型类的公共父类。

ConcretePrototype:具体原型类,实现了克隆方法,在克隆方法中返回自己的一个克隆对象。

Client:客户类,让一个原型对象克隆自身从而创建一个新的对象。

public interface ButtonClone {

    ButtonClone cloneBtn();

}

public class Button implements ButtonClone{

    private Double width;
    private Double height;

    public Double getWidth() {
        return width;
    }

    public void setWidth(Double width) {
        this.width = width;
    }

    public Double getHeight() {
        return height;
    }

    public void setHeight(Double height) {
        this.height = height;
    }

    @Override
    public ButtonClone cloneBtn() {
        Button newBtn = new Button();
        newBtn.setHeight(this.height);
        newBtn.setWidth(this.width);
        return newBtn;
    }
}

1 浅克隆与深克隆

浅克隆,如果源对象的成员变量是值类型,将复制一份给克隆对象,如果源对象的成员变量是引用类型,则将引用对象的地址复制一份给对象。

深克隆,无论源对象的成员变量是值类型还是引用类型,都将复制一份给目标对象。

1.1 浅克隆

Java的Object类提供了一个clone()方法,可以将一个Java对象浅克隆。能实现克隆Java类必须实现一个标识接口Cloneable,表示这个类支持被复制。

public class ConcretePrototype implements Cloneable{

    private String name;

    private String type;

    private List<String> list = new ArrayList<>();

    public ConcretePrototype(String name, String type) {
        this.name = name;
        this.type = type;
    }

    @Override
    public String toString() {
        return "ConcretePrototype{" +
                "name='" + name + '\'' +
                ", type='" + type + '\'' +
                ", list=" + list +
                '}';
    }

    public static void main(String[] args) throws CloneNotSupportedException {
        ConcretePrototype prototype = new ConcretePrototype("实际类型", "浅克隆");
        System.out.println("prototype:" + prototype);
        Object clone = prototype.clone();
        System.out.println("clone:" + clone);

        prototype.list.add("hello");
        System.out.println("clone:" + clone);
    }

}

1.2 深克隆

深克隆,除了对象本身被复制外,对象所包含的所有成员变量也将被复制。在Java中,如果需要实现深克隆,可以通过序列化等方式来实现。需要实例化的对象其类必须实现Serializable接口,否则无法实现序列化操作。

public class CusForm implements Serializable , Cloneable{

    private String name;
    private CusFile cusFile;

    public CusForm(String name, CusFile cusFile) {
        this.name = name;
        this.cusFile = cusFile;
    }

    public static void main(String[] args) throws IOException, ClassNotFoundException, CloneNotSupportedException {
        CusForm cusForm = new CusForm("表单", new CusFile());
        System.out.println(cusForm);
        System.out.println(cusForm.clone()); //java浅克隆,对象成员变量直接复制地址
        CusForm deepCloneObj = cusForm.deepClone();
        System.out.println(deepCloneObj);

//        运行结果
//        CusForm{name='表单', cusFile=com.huangmingfu.prototype.deep.CusForm$CusFile@1b6d3586}
//        CusForm{name='表单', cusFile=com.huangmingfu.prototype.deep.CusForm$CusFile@1ddc4ec2}
//        CusForm{name='表单', cusFile=com.huangmingfu.prototype.deep.CusForm$CusFile@1b6d3586}
    }

    public CusForm deepClone() throws IOException, ClassNotFoundException {
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream);
        objectOutputStream.writeObject(this);

        ByteArrayInputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());
        ObjectInputStream objectInputStream = new ObjectInputStream(inputStream);
        return (CusForm) objectInputStream.readObject();
    }

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

    private static class CusFile implements Serializable{}
}

2 原型管理器

将多个原型对象存储在一个集合中供客户端使用,它是一个专门复制克隆对象的工厂。其中定义了一个集合用于存储原型对象。

图 原型管理器

public class DeepClone implements Serializable {
    public DeepClone deepClone()  {
        try {
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream);
            objectOutputStream.writeObject(this);
            ByteArrayInputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());
            ObjectInputStream objectInputStream = new ObjectInputStream(inputStream);
            return (DeepClone)objectInputStream.readObject();
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
        return null;
    }
}

public class ConcreteA extends DeepClone{

    private final String name = "concreteA";

    @Override
    public String toString() {
        return "ConcreteA{" +
                "name='" + name + '\'' +
                '}' + super.toString();
    }

}

public class ConcreteB extends DeepClone{

    private final String name = "ConcreteB";

    @Override
    public String toString() {
        return "ConcreteB{" +
                "name='" + name + '\'' +
                '}' + super.toString();
    }
}

public class PrototypeManager {

    private final Map<Class<? extends DeepClone>,DeepClone> prototypeMap = new HashMap<>();
    private final Set<Class<? extends DeepClone>> classes = new HashSet<>();

    private PrototypeManager() {}

    private static class HolderClass {
        private final static PrototypeManager instance = new PrototypeManager();
    }

    public static PrototypeManager getInstance() {
        return HolderClass.instance;
    }

    public void addPrototype(DeepClone deepClone) {
        if (classes.add(deepClone.getClass())) {
            prototypeMap.put(deepClone.getClass(),deepClone);
        }
    }

    public DeepClone getClone(Class<? extends DeepClone> cls) {
        DeepClone deepClone = prototypeMap.get(cls);
        if (deepClone == null) {
            throw new RuntimeException("克隆体不存在");
        }
        return deepClone.deepClone();
    }

}

public class Client {

    public static void main(String[] args) {
        ConcreteA concreteA = new ConcreteA();
        ConcreteB concreteB = new ConcreteB();
        PrototypeManager prototypeManager = PrototypeManager.getInstance();

        System.out.println(concreteA);
        System.out.println(concreteB);

        prototypeManager.addPrototype(concreteA);
        prototypeManager.addPrototype(concreteB);
        System.out.println("克隆分割线---------------");
        DeepClone deepCloneA = prototypeManager.getClone(ConcreteA.class);
        DeepClone deepCloneB = prototypeManager.getClone(ConcreteB.class);

        System.out.println(deepCloneA);
        System.out.println(deepCloneB);

//        运行结果
//        ConcreteA{name='concreteA'}com.huangmingfu.prototype.manager.ConcreteA@1b6d3586
//        ConcreteB{name='ConcreteB'}com.huangmingfu.prototype.manager.ConcreteB@4554617c
//        克隆分割线---------------
//        ConcreteA{name='concreteA'}com.huangmingfu.prototype.manager.ConcreteA@30dae81
//        ConcreteB{name='ConcreteB'}com.huangmingfu.prototype.manager.ConcreteB@1b2c6ec2
    }

}

3 适用场景

当创建新的对象实例较为复杂时,使用原型模式可以简化对象的创建工厂,通过复制一个已有实例可以提高新实例的创建效率。

  1. 创建新对象成本较大。
  2. 对象的状态变化很小,且系统需要保存对象的状态时。
  3. 需要创建许多相似对象。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值