设计模式之原型模式

定义

原型模式是一种创建型设计模式,它通过复制现有对象(原型)来创建新对象,而不需要从头开始创建。这种模式允许我们在运行时根据需要动态地复制对象,同时保持高性能和最小化资源消耗。原型模式的核心在于定义了一个可以克隆自身的接口,这样就可以通过已经存在的实例来快速生成具有相同或相似状态的新实例,而不需要关注对象创建的具体细节。

使用场景

原型模式的使用场景包括但不限于以下几种情况:

  • 对象创建成本较高:当创建一个新对象需要消耗大量的资源(如大量数据加载、复杂的计算或外部系统交互)时,使用原型模式通过复制现有对象可以避免这些开销。
  • 初始化消耗资源多:如果类的初始化过程需要占用大量的硬件资源或数据准备,可以通过原型拷贝来复用已存在的实例,从而减少资源消耗。
  • 创建过程繁琐:当通过new操作创建对象需要进行复杂的设置或涉及多个步骤时,利用原型模式克隆一个已经配置好的对象可以简化这一过程。
  • 构造函数复杂:如果构造函数包含很多参数或者逻辑复杂,使用原型模式可以通过复制现有的实例来绕过复杂的构造过程。
  • 循环体中的对象创建:在循环体内频繁创建相似对象时,使用原型模式可以显著提高性能,因为克隆对象比每次循环都执行完整的构造过程更快。

原型设计模式的实现

在Java中,实现原型模式需要满足两个条件:原型类需要实现Cloneable接口和重写clone()方法。

下面是一个简单的示例代码:

import lombok.Data;
import java.util.ArrayList;
import java.util.List;

@Data
public class Person implements Cloneable {

    private String name;
    private List<String> hobbies;

    public Person(String name, List<String> hobbies) {
        this.name = name;
        this.hobbies = hobbies;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

    public static void main(String[] args) throws CloneNotSupportedException {
        // 兴趣爱好
        List<String> hobbies = new ArrayList<>();
        hobbies.add("读书");
        hobbies.add("听音乐");

        Person prototype = new Person("张三", hobbies);
        Person cloned = (Person) prototype.clone();
       
        // prototype: Person(name=张三, hobbies=[读书, 听音乐])
        System.out.println("prototype: "+ prototype);
        // cloned: Person(name=张三, hobbies=[读书, 听音乐])
        System.out.println("cloned: "+ cloned);
    }
}

💡Cloneable是Java中的一个标记接口,其内部没有定义任何方法和属性。实现这个接口的类表明该类的实例可以被克隆。当一个对象实现了Cloneable接口时,它可以通过覆盖Object类的clone方法来实现自身的浅拷贝或深拷贝。注意,clone方法默认实现的是浅拷贝。

浅拷贝和深拷贝

上面我们提到了浅拷贝与深拷贝的概念,接下来,我们将详细介绍一下这两种拷贝方式之间的区别,如下:

  • 浅拷贝:浅拷贝是指复制对象的基本数据类型或不可变对象(如字符串、基本类型的包装类)的属性值,但对于对象中的引用类型数据,仅复制其引用地址,不创建新的引用对象。因此,原对象与拷贝对象在引用类型属性上会共享同一块内存区域。这意味着,如果你修改了拷贝对象中的引用类型属性,原对象的相应属性也会受到影响,反之亦然。
  • 深拷贝:与浅拷贝不同的是,深拷贝涉及到的不仅是复制对象的基本类型数据,还包括所有层级的引用类型数据的复制。这意味着,每一个被引用的对象都会被重新创建,确保新对象完全独立于原对象。

现在,让我们对上述示例代码进行简单修改以演示深拷贝的过程。代码如下所示:

@Data
public class Person implements Cloneable {

    private String name;
    private List<String> hobbies;

    public Person(String name, List<String> hobbies) {
        this.name = name;
        this.hobbies = hobbies;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        Person clonePerson  = (Person) super.clone();
        clonePerson.hobbies = new ArrayList<>(this.hobbies);
        return clonePerson;
    }

    public static void main(String[] args) throws CloneNotSupportedException {
        // 兴趣爱好
        List<String> hobbies = new ArrayList<>();
        hobbies.add("读书");
        hobbies.add("听音乐");

        Person prototype = new Person("张三", hobbies);
        Person cloned = (Person) prototype.clone();

        // 证明是深拷贝,修改cloned的hobbies不会影响到prototype的hobbies
        cloned.hobbies.add("旅游");

        // prototype: Person(name=张三, hobbies=[读书, 听音乐])
        System.out.println("prototype: "+ prototype);
        // cloned: Person(name=张三, hobbies=[读书, 听音乐, 旅游])
        System.out.println("cloned: "+ cloned);
    }
}

除了上述的实现方式,我们还可以利用序列化与反序列化的过程来实现深拷贝。代码如下所示:

@Data
public class Person implements Serializable {

    private static final long serialVersionUID = 1L;

    private String name;
    private List<String> hobbies;

    public Person(String name, List<String> hobbies) {
        this.name = name;
        this.hobbies = hobbies;
    }

    public Person deepCopy() throws IOException, ClassNotFoundException {
        try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
             ObjectOutputStream oos = new ObjectOutputStream(bos)) {
            // 序列化
            oos.writeObject(this);

            try (ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
                 ObjectInputStream ois = new ObjectInputStream(bis)) {
                // 反序列化
                return (Person) ois.readObject();
            }
        }
    }

    public static void main(String[] args) throws IOException, ClassNotFoundException {
        // 兴趣爱好
        List<String> hobbies = new ArrayList<>();
        hobbies.add("读书");
        hobbies.add("听音乐");

        Person prototype = new Person("张三", hobbies);
        Person cloned = prototype .deepCopy();
        cloned .getHobbies().add("旅行");

        // prototype: Person(name=张三, hobbies=[读书, 听音乐])
        System.out.println("prototype: " + prototype);
        // cloned: Person(name=张三, hobbies=[读书, 听音乐, 旅行])
        System.out.println("cloned: " + cloned);
    }
}

总结

原型设计模式是一种强大的设计模式,它允许我们通过复制对象来创建新的对象,从而提高了对象的创建效率。在实际开发中,我们可以根据具体的需求和场景来选择合适的设计模式,以提高代码的可读性、可维护性和可扩展性。通过本文的介绍,相信你已经对原型设计模式有了更深入的了解。希望你在未来的开发中能够灵活运用这一设计模式,为你的项目带来更好的性能和可维护性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

沉迷学习的咸鱼

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

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

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

打赏作者

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

抵扣说明:

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

余额充值