原型模式:深拷贝与浅拷贝的比较与选择

码农日志 2019-03-21 ⋅ 3 阅读

在软件开发中,原型模式(Prototype Pattern)是一种创建型设计模式,它允许通过复制现有对象来创建新对象,而无需从头开始编写代码。通过使用原型模式,我们可以避免创建新对象时的复杂初始化过程,大大提高代码的可复用性。然而,在使用原型模式时,我们需要注意拷贝的方式,特别是深拷贝(Deep Copy)和浅拷贝(Shallow Copy)之间的区别。

浅拷贝

浅拷贝是指在拷贝对象时,仅拷贝对象的引用或者指针,而并不复制对象本身。这意味着新对象和原始对象共享同一个内存地址,对其中一个对象的修改会影响到另一个对象。

public class Person implements Cloneable {
    private String name;
    private Address address;
    
    // 构造函数、getter和setter略
    
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

public class Address {
    private String city;
    // 省略其他属性和方法
}

现在,我们创建一个 Person 对象,并进行浅拷贝操作:

Person john = new Person("John", new Address("New York"));
Person johnCopy = (Person) john.clone();

johnCopy.setName("John Smith");
johnCopy.getAddress().setCity("San Francisco");

System.out.println(john.getName()); // 输出 "John Smith"
System.out.println(john.getAddress().getCity()); // 输出 "San Francisco"

可以看到,浅拷贝之后,修改了拷贝对象 johnCopy 的属性,原对象 john 也发生了改变。

深拷贝

深拷贝是指在拷贝对象时,完全复制对象及其所有属性的值,通过重新创建一份独立的内存空间来存储。新对象的修改不会影响原始对象。

要实现深拷贝,我们可以使用序列化和反序列化的方式,或者手动递归复制每个属性。

public class Person implements Cloneable, Serializable {
    private String name;
    private Address address;
    
    // 构造函数、getter和setter略
    
    @Override
    protected Object clone() throws CloneNotSupportedException {
        try {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(baos);
            oos.writeObject(this);
            
            ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(bais);
            return ois.readObject();
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
            return null;
        }
    }
}

public class Address implements Serializable {
    private String city;
    // 省略其他属性和方法
}

现在,我们使用深拷贝方式创建新对象:

Person john = new Person("John", new Address("New York"));
Person johnCopy = (Person) john.clone();

johnCopy.setName("John Smith");
johnCopy.getAddress().setCity("San Francisco");

System.out.println(john.getName()); // 输出 "John"
System.out.println(john.getAddress().getCity()); // 输出 "New York"

可以看到,深拷贝之后,修改拷贝对象 johnCopy 的属性,原对象 john 不受影响。

如何选择

要选择使用深拷贝还是浅拷贝,需要根据具体的业务需求和对象间的关系来决定。

如果对象的属性中包含了不可变对象(如 String)或者引用对象的修改不会对其他对象造成影响,那么可以选择浅拷贝。这样可以节省资源,提高性能。

另一方面,如果对象的属性为可变对象,而且希望在拷贝时完全独立复制,那么应该选择深拷贝。这样可以保证对象之间的独立性,避免修改一个对象对其他对象产生意外影响。

需要注意的是,在实现深拷贝时,拷贝的对象及其所有引用对象都需要实现 Serializable 接口,否则无法进行序列化和反序列化操作。

综上所述,我们在使用原型模式时,应根据具体情况权衡选择进行深拷贝还是浅拷贝,以实现最合适的对象复制方式。

参考资料:


全部评论: 0

    我有话说: