以下是 原型模式 (Prototype Pattern) 的详细介绍,包含定义、优缺点、应用场景及代码实现:
clone()
方法实现对象的快速复制,支持动态扩展对象类型。
Cloneable
接口,可能违反某些设计原则(如接口隔离)。
clone()
方法可能访问私有字段,需谨慎实现。
以下通过 文档模板复制 的案例演示原型模式,包含浅拷贝与深拷贝实现:
import java.util.List;
/**
* 原型类:文档模板(实现 Cloneable 接口)
*/
public class DocumentTemplate implements Cloneable {
private String title;
private List<String> paragraphs; // 引用类型(浅拷贝共享该引用)
public DocumentTemplate(String title, List<String> paragraphs) {
this.title = title;
this.paragraphs = paragraphs;
}
/**
* 浅拷贝实现:直接调用 Object.clone()
*/
@Override
public DocumentTemplate clone() throws CloneNotSupportedException {
return (DocumentTemplate) super.clone();
}
// 修改标题(演示浅拷贝影响)
public void setTitle(String title) {
this.title = title;
}
// 添加段落(演示浅拷贝问题)
public void addParagraph(String text) {
paragraphs.add(text);
}
@Override
public String toString() {
return "Title: " + title + "\nContent: " + String.join("\n", paragraphs);
}
}
public class Client {
public static void main(String[] args) throws CloneNotSupportedException {
// 原始文档
List<String> paragraphs = new ArrayList<>(List.of("第一段", "第二段"));
DocumentTemplate original = new DocumentTemplate("原始文档", paragraphs);
// 浅拷贝副本
DocumentTemplate copy = original.clone();
copy.setTitle("副本文档"); // 修改基本类型字段(不影响原对象)
copy.addParagraph("新增段落"); // 修改引用类型字段(影响原对象!)
System.out.println("--- 原文档 ---\n" + original);
System.out.println("--- 副本 ---\n" + copy);
}
}
--- 原文档 ---
Title: 原始文档
Content: 第一段
第二段
新增段落 // 原对象的 paragraphs 被修改!
--- 副本 ---
Title: 副本文档
Content: 第一段
第二段
新增段落
/**
* 深拷贝原型类:通过手动复制引用对象
*/
public class DeepDocumentTemplate implements Cloneable {
private String title;
private List<String> paragraphs;
public DeepDocumentTemplate(String title, List<String> paragraphs) {
this.title = title;
this.paragraphs = new ArrayList<>(paragraphs); // 防御性拷贝
}
/**
* 深拷贝实现:手动创建新对象
*/
@Override
public DeepDocumentTemplate clone() {
// 1. 基本类型字段直接复制
String clonedTitle = this.title;
// 2. 引用类型字段创建新实例
List<String> clonedParagraphs = new ArrayList<>(this.paragraphs);
return new DeepDocumentTemplate(clonedTitle, clonedParagraphs);
}
// 省略其他方法...
}
public class Client {
public static void main(String[] args) {
List<String> paragraphs = new ArrayList<>(List.of("第一段", "第二段"));
DeepDocumentTemplate original = new DeepDocumentTemplate("原始文档", paragraphs);
DeepDocumentTemplate copy = original.clone();
copy.setTitle("副本文档");
copy.addParagraph("新增段落");
System.out.println("--- 原文档 ---\n" + original);
System.out.println("--- 副本 ---\n" + copy);
}
}
--- 原文档 ---
Title: 原始文档
Content: 第一段
第二段
--- 副本 ---
Title: 副本文档
Content: 第一段
第二段
新增段落
+----------------+ +----------------+
| Prototype | | Client |
+----------------+ +----------------+
| clone():Prototype | |
+----------------+ +----------------+
^ |
| |
+----------------+ +----------------+
| ConcretePrototype | |
+----------------+ +----------------+
| clone():Prototype | |
+----------------+ +----------------+
ObjectOutputStream
)或工具库(Apache Commons Lang 的 SerializationUtils
)简化深拷贝。
clone()
方法无法修改 final 字段,需谨慎设计。
Cloneable
接口 + 重写 clone()
方法 + 处理深拷贝。
Java 中 ArrayList
、HashMap
等集合类均实现了 clone()
方法,是原型模式的典型应用。合理使用该模式可显著提升系统性能与灵活性。