Java设计模式系列 原型模式解读(超通俗易懂)

本文介绍了Java中的原型模式,包括其原理、选择原因、应用场景,重点讲解了浅克隆和深克隆的区别与联系,以及如何在实践中实现这两种克隆方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


一、什么是原型模式?(理论)

Java原型模式是一种创建型设计模式,它通过复制现有对象的实例来创建新的对象实例。使用该模式可以有效的减少对象创建的时间和资源消耗,特别是在创建复杂对象的时候。(大白话:在Java中,对象的创建通常是使用关键字“new”进行创建的,但是如果使用原型模式,我们可以通过克隆现有对象来创建新的对象,而不需要重新实例化和初始化新的对象。)

官方原文:Specify the kinds of objects to create using a prototypical instance,and create new objects by copying this prototype.

特殊强调:原型模式的核心在于克隆拷贝原型对象,以系统中已存在的一个对象为原型,直接基于内存二进制流进行拷贝,无需再经历耗时的对象初始化过程,使得性能提升

二、为什么选择原型模式

  • 减少对象的创建时间和资源消耗:Java原型模式可以避免重复创建相似对象,特别是在创建复杂对象时,能够显著减少创建时间和资源消耗。
  • 保护对象的私有状态:Java原型模式可以避免暴露对象的创建细节,从而保护对象的私有状态。
  • 提高代码的可维护、可扩展性:Java原型模式避免了重复的代码,同时也方便了代码的修改和调试,在处理复杂对象的构建过程时,Java原型模式能够提高代码的可维护性和可扩展性。

三、原型模式应用场景

  • 类初始化消耗资源较多
  • new 产生的对象是一个非常繁琐的过程
  • 构造函数很复杂
  • 循环体中需要生产大量对象

四、必须搞懂东西:浅克隆和深克隆

浅克隆

是指仅仅复制对象的基本数据类型属性,而不复制对象的引用类型属性。这意味着克隆对象和原型对象是共享同一个引用类型属性,如果更改克隆对象或者原型对象中的引用类型属性,则会影响到另外一个对象。

实现浅克隆非常简单,我们只需要实现Cloneable接口,再重写Object类中的clone()方法即可。注:Cloneable接口里面什么都没有,是一个标记接口。

public interface Cloneable {
}

浅克隆案例:

先创建一个ConcretePrototype 类,实现Cloneable

@Data
public class ConcretePrototype implements Cloneable {

    private int age;

    private String name;

    private List<String> hobbies;

    @Override
    public ConcretePrototype clone() {
        try {
            return (ConcretePrototype) super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
            return null;
        }
    }

}

创建一个Client对象进行测试

public class Client {

    public static void main(String[] args) {
        //创建原型对象
        ConcretePrototype prototype = new ConcretePrototype();
        prototype.setAge(18);
        prototype.setName("Tom");
        List<String> hobbies = new ArrayList<>();
        hobbies.add("书法");
        hobbies.add("美术");
        prototype.setHobbies(hobbies);

        //拷贝原型对象
        ConcretePrototype cloneType = prototype.clone();
        System.out.println("原型对象:" + prototype);
        System.out.println("克隆对象:" + cloneType);
        System.out.println(prototype == cloneType);

        System.out.println("原型对象的爱好:" + prototype.getHobbies());
        System.out.println("克隆对象的爱好:" + cloneType.getHobbies());
        System.out.println(prototype.getHobbies() == cloneType.getHobbies());
    }

}

打印结果如图所示,此时我们成功完成了一次浅克隆操作。

在这里插入图片描述

为了验证此次拷贝是浅克隆,我们修改部分main方法的代码

public class Client {

    public static void main(String[] args) {
        //创建原型对象
        ConcretePrototype prototype = new ConcretePrototype();
        prototype.setAge(18);
        prototype.setName("Tom");
        List<String> hobbies = new ArrayList<>();
        hobbies.add("书法");
        hobbies.add("美术");
        prototype.setHobbies(hobbies);

        //拷贝原型对象
        ConcretePrototype cloneType = prototype.clone();
        System.out.println("原型对象:" + prototype);
        System.out.println("克隆对象:" + cloneType);
        System.out.println(prototype == cloneType);

        System.out.println("原型对象的爱好:" + prototype.getHobbies());
        System.out.println("克隆对象的爱好:" + cloneType.getHobbies());
        System.out.println(prototype.getHobbies() == cloneType.getHobbies());

        System.out.println("-----------------------------分割线-----------------------------------");

        cloneType.getHobbies().add("技术控");
        prototype.setHobbies(hobbies);
        System.out.println("原型对象的爱好:" + prototype.getHobbies());
        System.out.println("克隆对象的爱好:" + cloneType.getHobbies());
        prototype.setAge(20);
        System.out.println("原型对象的年龄:" + prototype.getAge());
        System.out.println("克隆对象的年龄:" + cloneType.getAge());
        prototype.setName("Alex");
        System.out.println("原型对象的姓名:" + prototype.getName());
        System.out.println("克隆对象的姓名:" + cloneType.getName());
    }
}

打印结果如下图所示,我们能够看到 name age都是成功修改并且互补影响,而List<String> hobbies 虽修改成功但此处我是修改的克隆对象的,原型对象也受到影响,因此能够证明此次克隆是一次浅克隆

在这里插入图片描述

深克隆

是指复制对象及其所有引用类型属性。这意味着克隆对象和原型对象不共享同一个引用类型属性,更改克隆对象或者原型对象的引用类型属性不会影响到另一个对象。

要想要实现深克隆,一般两种方式:

  • 序列化和反序列化:将对象序列化为字节流,然后再反序列化为新的对象,这样可以创建一个与原型对象完全独立的克隆对象。
  • 逐个复制引用类型属性:对于每个引用类型的属性,创建一个新的实例并将原型对象属性的内容复制到新的实例中。

不过值得注意的是并非所有对象都能进行深拷贝。有两种情况:1、某些对象或者类中的属性可能是不可变的无需拷贝 2、某些对象可能包含循环引用,

深克隆案例:
我们只需要修改一下clone()方法即可实现,代码如下,自行测试 自行阅读。

    @Override
    public ConcretePrototype clone() {
     try {
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(bos);
            oos.writeObject(this);
            ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(bis);
            return (ConcretePrototype)ois.readObject();
        }catch (Exception e){
            e.printStackTrace();
            return null;
        }
    }

总结:区别与联系

总的来说:深克隆和浅克隆最主要的区别是引用类型属性的处理方式不同。浅克隆只克隆对象本身以及对象内部的基本数据类型,原型对象和克隆对象共享同一引用类型属性的访问,且如果其中一个对象的引用类型属性进行了修改,那么另一个对象也会受到影响;而深克隆还会递归地复制对象内部引用类型属性,深克隆创建的是一个完全独立的新对象,和原始对象没有任何关联

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值