原型模式(Prototype Pattern)
原型模式(Prototype Pattern)用于创建重复的对象,同时又能保证性能。它属于创建型设计模式,使用现有的实例来创建新对象,而不是每次都通过实例化来创建新对象。原型模式通过克隆已有对象来创建新的实例。
原型模式的应用场景
- 对象初始化消耗大量资源:如需要加载大量数据或建立复杂的网络连接。
- 创建新对象的代价昂贵:如涉及到复杂的计算或繁琐的配置。
- 系统需要大量类似对象:如需要创建大量类似的文档、图形或对象。
- 避免类层次结构的复杂性:如避免使用构造器或工厂模式的复杂创建逻辑。
原型模式的实现方式
1. 使用 Cloneable
接口实现浅拷贝
思想:实现 Cloneable
接口,并重写 clone
方法,通过浅拷贝来创建对象的副本。浅拷贝只复制对象的基本类型字段和引用类型字段的引用,而不复制引用类型字段指向的对象。
实现方式:
class Prototype implements Cloneable {
private String field;
public Prototype(String field) {
this.field = field;
}
public String getField() {
return field;
}
public void setField(String field) {
this.field = field;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public class PrototypePattern {
public static void main(String[] args) {
try {
Prototype original = new Prototype("Original");
Prototype clone = (Prototype) original.clone();
System.out.println("Original: " + original.getField());
System.out.println("Clone: " + clone.getField());
clone.setField("Clone");
System.out.println("Original after modifying clone: " + original.getField());
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}
}
优点:
- 实现简单,直接使用 Java 提供的
Cloneable
接口。
缺点:
- 浅拷贝仅复制基本类型字段和引用类型字段的引用,不复制引用类型字段指向的对象,可能导致共享引用问题。
2. 实现深拷贝
思想:通过序列化和反序列化,或手动复制引用类型字段,来实现对象的深拷贝。深拷贝不仅复制对象的基本类型字段,还复制引用类型字段指向的对象。
实现方式:
- 使用序列化实现深拷贝:
import java.io.*;
class PrototypeDeep implements Serializable {
private static final long serialVersionUID = 1L;
private String field;
public PrototypeDeep(String field) {
this.field = field;
}
public String getField() {
return field;
}
public void setField(String field) {
this.field = field;
}
public PrototypeDeep deepClone() {
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 (PrototypeDeep) ois.readObject();
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
return null;
}
}
}
public class PrototypePatternDeepCopy {
public static void main(String[] args) {
PrototypeDeep original = new PrototypeDeep("Original");
PrototypeDeep clone = original.deepClone();
System.out.println("Original: " + original.getField());
System.out.println("Clone: " + clone.getField());
clone.setField("Clone");
System.out.println("Original after modifying clone: " + original.getField());
}
}
优点:
- 深拷贝可以完全独立地复制对象,包括其引用类型字段所指向的对象,避免共享引用问题。
缺点:
- 序列化和反序列化开销较大。
- 需要确保所有引用类型字段实现
Serializable
接口。
- 手动实现深拷贝:
class InnerObject implements Cloneable {
private String innerField;
public InnerObject(String innerField) {
this.innerField = innerField;
}
public String getInnerField() {
return innerField;
}
public void setInnerField(String innerField) {
this.innerField = innerField;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
class PrototypeManualDeep implements Cloneable {
private String field;
private InnerObject innerObject;
public PrototypeManualDeep(String field, InnerObject innerObject) {
this.field = field;
this.innerObject = innerObject;
}
public String getField() {
return field;
}
public void setField(String field) {
this.field = field;
}
public InnerObject getInnerObject() {
return innerObject;
}
public void setInnerObject(InnerObject innerObject) {
this.innerObject = innerObject;
}
@Override
protected Object clone() throws CloneNotSupportedException {
PrototypeManualDeep clone = (PrototypeManualDeep) super.clone();
clone.innerObject = (InnerObject) innerObject.clone();
return clone;
}
}
public class PrototypePatternManualDeepCopy {
public static void main(String[] args) {
InnerObject innerObject = new InnerObject("InnerOriginal");
PrototypeManualDeep original = new PrototypeManualDeep("Original", innerObject);
PrototypeManualDeep clone;
try {
clone = (PrototypeManualDeep) original.clone();
System.out.println("Original: " + original.getField() + ", Inner: " + original.getInnerObject().getInnerField());
System.out.println("Clone: " + clone.getField() + ", Inner: " + clone.getInnerObject().getInnerField());
clone.setField("Clone");
clone.getInnerObject().setInnerField("InnerClone");
System.out.println("Original after modifying clone: " + original.getField() + ", Inner: " + original.getInnerObject().getInnerField());
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}
}
优点:
- 通过手动实现深拷贝,可以精确控制拷贝的过程。
缺点:
- 手动实现深拷贝代码复杂,容易出错。
- 需要为每个引用类型字段单独实现拷贝逻辑。
总结
实现方式 | 优点 | 缺点 |
---|---|---|
浅拷贝 | 实现简单,直接使用 Cloneable 接口 | 仅复制基本类型字段和引用类型字段的引用,可能导致共享引用问题 |
深拷贝(序列化实现) | 完全独立地复制对象,包括引用类型字段所指向的对象,避免共享引用问题 | 序列化和反序列化开销较大,需要确保所有引用类型字段实现 Serializable 接口 |
深拷贝(手动实现) | 精确控制拷贝过程 | 代码复杂,容易出错,需要为每个引用类型字段单独实现拷贝逻辑 |
选择哪种实现方式应根据具体的应用场景和需求来决定。如果对象较为简单且不涉及复杂的引用类型字段,可以使用浅拷贝。如果对象复杂且需要完全独立的副本,可以选择序列化实现深拷贝或手动实现深拷贝。