创建型模式-原型(Prototype)-解决复制创建对象问题-浅拷贝深拷贝
创建型模式-原型Prototype-解决复制创建对象问题-浅拷贝深拷贝
- 创建型模式
- 原型(Prototype)
- 解决复制创建对象问题
- 描述
- 适用环境
- 优点:
- 缺点:
- 违反原则
- 实现方式
- 浅拷贝
- 深拷贝
- 代码实现
- 实现小结
- 注意点:
创建型模式
原型(Prototype)
解决复制创建对象问题
描述
通过克隆现有对象来创建新对象,从而避免了重复创建相似对象的过程,同时也能够提高对象创建的效率。这种方式可以使得对象的创建更加灵活、动态,并且能够避免成本高昂的构造过程。
适用环境
需要创建大量相似对象,并且这些对象之间的差异较小。创建新对象的成本比较大或者比较困难,例如包含的组件较多或者涉及到网络通信等操作。
优点:
可以避免昂贵的初始化操作。
可以通过克隆现有对象来创建新的对象实例,避免了重复代码的编写。可以动态地增加或减少对象数量。
缺点:
如果需要克隆的对象较为复杂,需要深度克隆才能确保每个属性都被正确地复制,可能会导致性能问题。需要对每个需要克隆的类进行克隆方法的实现,如果需要克隆的类比较多,则会增加系统的复杂度。
违反原则
可能违反单一职责原则:原型对象必须能够复制自身,而且需要维护原型对象的状态。
实现方式
浅拷贝
浅拷贝是指在复制对象时仅仅复制对象本身和其所有的基本数据类型成员变量的值,而不复制对象所引用的其他对象。在Java中,Object类提供了一个clone()方法来实现浅拷贝。
深拷贝
深拷贝是一种完全复制对象及其所有引用类型成员变量的值的方式。在Java中,可以通过序列化和反序列化来实现深拷贝。另外,也可以通过递归地克隆每个成员变量来实现深拷贝。
在进行深拷贝时可能会遇到无限递归的问题,因为一个对象可能引用另一个对象,而后者又引用前者,这将导致无限循环。为避免这种情况,可以使用标记、缓存或序列化等技术来解决。
代码实现
一个书籍类包含三个属性:书名、作者和ISBN号码。创建一个新的对但某些属性可能与现有对象相同为避免重复输入这些属性值
可以使用原型模式来创建并克隆现有对象,下面是一个基于上述例子的Java代码实现:
//书籍类
class Book implements Cloneable {
private String title;
private String author;
private String isbn;
public Book(String title, String author, String isbn) {
this.title = title;
this.author = author;
this.isbn = isbn;
}
// 浅拷贝方法
public Book shallowCopy() throws CloneNotSupportedException {
return (Book) super.clone();
}
// 深拷贝方法
public Book deepCopy() throws IOException, ClassNotFoundException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(this);
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
return (Book) ois.readObject();
}
}
在代码示例中书籍类实现了Cloneable接口并覆盖了其中的clone()方法来实现浅拷贝。
定义了一个deepCopy()方法来实现深拷贝。
在实现深拷贝时使用了Java中的序列化和反序列化来克隆Book对象及其所有引用类型成员变量的值。
下面是如何使用浅拷贝和深拷贝来创建和克隆书籍对象:
public class Main {
public static void main(String[] args) throws CloneNotSupportedException, IOException, ClassNotFoundException {
// 创建原始对象
Book book1 = new Book("战争与和平", "列夫·托尔斯泰", "978-7-111-54803-2");
// 浅拷贝对象
Book book2 = book1.shallowCopy();
System.out.println(book1 == book2); // 输出false
System.out.println(book1.getTitle() == book2.getTitle()); // 输出true
// 深拷贝对象
Book book3 = book1.deepCopy();
System.out.println(book1 == book3); // 输出false
System.out.println(book1.getTitle() == book3.getTitle()); // 输出false
}
}
实现小结
在示例中,
创建原始的Book对象book1使用shallowCopy()方法进行浅拷贝并将结果存储在book2中。
之后比较了book1和book2的地址和标题属性是否相同,并发现它们的地址不同但标题属性相同。这说明book2是通过浅拷贝从book1复制而来的,且它们共享了标题属性。
使用deepCopy()方法进行深拷贝并将结果存储在book3中。再次比较了book1和book3的地址和标题属性是否相同,发现地址和标题属性都不相同。说明book3是通过深拷贝从book1复制而来的,并且它们的所有属性都被完全克隆了一份。
注意点:
实现深拷贝时Book类及其所有引用类型成员变量都必须是可序列化的,否则将无法使用序列化技术进行深拷贝。
当对象的结构非常复杂时使用深拷贝可能会导致性能下降,因为需要进行大量的序列化和反序列化操作。
这种情况下可以考虑使用其他技术来实现对象的复制,如手动编写递归方法来克隆所有成员变量,或者使用第三方库来简化深拷贝的实现过程。