【原型模式】原型模式深入分析

本文深入介绍了Java中的原型模式,包括其概念、应用场景、通用实现方式及深浅克隆的区别。通过示例展示了如何使用原型模式创建和克隆对象,并探讨了原型模式在Spring框架中的应用。同时,文章还提到了原型模式的优缺点,以及在实现深克隆时可能遇到的问题及其解决方案。
摘要由CSDN通过智能技术生成

1. 原型模式

原型模式(Prototype Pattern)是指原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象,属于创建型模式
原型模式的核心在于拷贝原型对象,以系统中已存在的一个对象为原型,直接基于内存二进制流进行拷贝,无需再经历耗时对象初始化过程(不调用构造函数),性能提升许多,当对象的构建过程比较耗时时,可以利用当前系统中已存在的对象作为原型,对其进行克隆(一般是基于二进制流的复制)。躲避初始化过程,使得新对象的创建时间大大减少。
结构图如下所示:
在这里插入图片描述从UML图中,我们可以看到,原型模式主要包含三个角色:
客户(Client):客户类提出创建对象的请求。
抽象原型(Prototype):规定拷贝借口。
具体原型(Concrete Prototype):被拷贝的对象。

2.原型模式的应用场景

1.大篇幅 getter, setter 赋值的场景。
2.类初始化消耗资源较多。
3.new 产生的一个对象需要非常繁琐的过程(数据准备,访问权限等)
4.构造函数比较复杂。
5.循环体中产生大量对象时。

在Spring中,原型模式应用得非常广泛,例如:我们经常使用的 JSON.parseObject() 也是一种原型模式。

3. 原型模式的通用写法

3.1 先创建 IProtoType 接口

public interface IProtoType<T> {

    T clone();

}

3.2 创建具体需要克隆的类

@Data
public class ConcretePrototype implements Serializable, IProtoType {

    private static final long serialVersionUID = -7318203310711047606L;

    private String title;

    private String orignalValue;

    private Integer status;

    private String thumbnail;

    @Override
    public ConcretePrototype clone() {
        ConcretePrototype  concretePrototype = new ConcretePrototype();
        concretePrototype.setTitle(this.title);
        concretePrototype.setOrignalValue(this.orignalValue);
        concretePrototype.setStatus(this.status);
        concretePrototype.setThumbnail(this.thumbnail);
        return concretePrototype;
    }

    @Override
    public String toString() {
        return "ConcretePrototype{" +
                "title='" + title + '\'' +
                ", orignalValue='" + orignalValue + '\'' +
                ", status=" + status +
                ", thumbnail='" + thumbnail + '\'' +
                '}';
    }
}

3.3 测试代码:

public class ConcretePrototypeTest {

    public static void main(String[] args) {
        ConcretePrototype concretePrototype = new ConcretePrototype();
        concretePrototype.setTitle("图书");
        concretePrototype.setStatus(1001);
        System.out.println(concretePrototype);
        ConcretePrototype clone = concretePrototype.clone();
        System.out.println(clone);
    }
}
3.3.1 运行结果:

在这里插入图片描述原型模式就是这么简单,但是在实际开发过程中 JDK 已经帮我们实现了一个API, 我们只需要实现Cloneable接口即可,修改 ConcretePrototype 类:
在这里插入图片描述 直接运行,也会得到同样的结果。有了JDK的支持再多的属性复制我们也可以实现。
当我们新增一个属性的时候,我们会发现原型对象也发生了变化,这显然不符合我们的预期。因为我们希望克隆出来的对象应该和原型对象时两个独立的对象,不应该再有联系,应该是共用了一个内存地址,意味着复制的不是值,而是引用的地址。

浅克隆:

只是完整复制了值类型数据,没有赋值引用对象,换言之,所有的引用对象仍然指向原来的对象。

深克隆:

完整复制了值类型数据,并赋值引用对象,换言之,所有的引用对象仍然指向新的对象。

4. 使用序列化实现深度克隆

ConcretePrototype 类新增deepClone()方法。

    public ConcretePrototype 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  (ConcretePrototype)objectInputStream.readObject();
        }catch (Exception e ){
            e.printStackTrace();
            return null;
        }
    }

运行程序,我们会发现我们得到我们期望的结果:
在这里插入图片描述注: 克隆模式会破坏单例模式。如果我们克隆的目标的对象时单例对象,那意味着,深克隆就会破坏单例。
解决方案:禁止深克隆,不实现Cloneable接口,要么重新clone()方法。

5. 原型模式在源码中的应用

1.JDK中Cloneable接口。
2.ArrayList 类的实现,

6. 原型模式的优缺点

优点:
1,性能优良,Java自带的原型模式是基于内存二进制流的拷贝,比直接new一个对象性能提升了许多。
2,可以使用深克隆方式保存对象的状态,使用原型模式将对象复制一份并将其状态保存起来简化了创建对象的过程,以便在需要的时候使用。

缺点:
1.需要为每一个类配置一个克隆方法。
2.克隆方法位于类的内部,当对已有类进行改造的时候,需要修改代码,违反了开闭原则。
3.在实现深克隆时需要编写较为复杂的代码,而且当对象之间存在多重嵌套引用时,为了实现深克隆,每一层对象对应的类都必须支持深克隆,实现起来比较麻烦,因此,深拷贝,浅拷贝,需要谨慎使用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱吃薄荷味的口香糖

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值