一、原型模式介绍
原型模式是一种创建型设计模式,它允许我们通过克隆已有对象来创建新对象,而无需通过实例化来进行创建。
在原型模式中,我们定义一个原型接口或类,该接口或类声明了一个克隆方法。具体的原型类实现这个克隆方法,以便可以克隆自身。当客户端需要创建一个新对象时,它可以使用一个原型对象作为模板,并通过克隆方法来克隆这个原型对象,从而创建一个新对象。
二、原型模式代码示例
下面是一个原型模式的示例代码:
//1.原型接口
public interface Prototype {
Prototype clone();
}
//2.具体原型类
public class ConcretePrototype implements Prototype {
private int value;
public ConcretePrototype(int value) {
this.value = value;
}
public int getValue() {
return value;
}
@Override
public Prototype clone() {
return new ConcretePrototype(value);
}
}
//3.测试方法
public static void main(String[] args) {
ConcretePrototype prototype = new ConcretePrototype(10);
ConcretePrototype clone = (ConcretePrototype) prototype.clone();
System.out.println("prototype value: " + prototype.getValue());
System.out.println("clone value: " + clone.getValue());
}
在上面的代码中,Prototype
是原型接口,它定义了一个克隆方法。ConcretePrototype
是具体原型类,它实现了Prototype
接口,并为克隆方法提供了具体的实现。在测试代码中,我们创建了一个ConcretePrototype
对象,并使用克隆方法来创建了一个新对象。我们还可以通过修改原型对象来影响克隆对象的属性值。
原型模式可以很好地解决某些场景下的对象创建问题,特别是在创建对象的过程比较复杂或者耗时的情况下。原型模式可以大大简化对象创建的过程,提高代码复用性和可维护性。但是,需要注意的是,在使用原型模式时,克隆出来的新对象可能与原始对象存在一定的关联性,需要在使用时进行特殊处理。
三、深克隆和浅克隆(深复制和浅复制)
在 Java 中,对象的复制分为两种类型:深复制和浅复制。它们的区别在于复制后新对象与原始对象之间的关联性。
浅复制是指复制一个对象,新对象与原始对象共享同一个引用类型的数据成员(如数组、集合、对象等),因此对于这些共享的数据成员的修改会影响到所有引用它们的对象,包括原始对象和复制对象。
深复制则是指复制一个对象,新对象与原始对象不共享任何引用类型的数据成员,即它们之间的数据成员完全独立。因此对于新对象的修改不会影响到原始对象。
在 Java 中,通过实现 Cloneable 接口和重写 Object 类中的 clone() 方法来实现对象的复制。对于浅复制,直接调用 Object 类的 clone() 方法即可;对于深复制,需要在 clone() 方法中对引用类型的数据成员进行递归复制。
下面是一个使用浅复制和深复制的示例代码:
//定义一个包含引用类型数据成员的类
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;
}
public String getName() {
return name;
}
public List<String> getHobbies() {
return hobbies;
}
// 浅复制
public Person shallowCopy() throws CloneNotSupportedException {
return (Person) super.clone();
}
// 深复制
public Person deepCopy() throws CloneNotSupportedException {
Person clone = (Person) super.clone();
clone.hobbies = new ArrayList<>(this.hobbies);
return clone;
}
public static void main(String[] args) throws CloneNotSupportedException {
// 创建一个原始对象
List<String> hobbies = new ArrayList<>();
hobbies.add("reading");
hobbies.add("swimming");
Person original = new Person("Tom", hobbies);
// 浅复制一个新对象
Person shallowCopy = original.shallowCopy();
System.out.println("shallowCopy: " + shallowCopy.getName() + ", " + shallowCopy.getHobbies());
shallowCopy.getHobbies().add("travel");
System.out.println("original: " + original.getName() + ", " + original.getHobbies());
// 深复制一个新对象
Person deepCopy = original.deepCopy();
System.out.println("deepCopy: " + deepCopy.getName() + ", " + deepCopy.getHobbies());
deepCopy.getHobbies().add("coding");
System.out.println("original: " + original.getName() + ", " + original.getHobbies());
}
}
输出结果:
shallowCopy: Tom, [reading, swimming]
original: Tom, [reading, swimming, travel]
deepCopy: Tom, [reading, swimming, travel]
original: Tom, [reading, swimming, travel]
在上面的代码中,Person
是一个包含引用类型数据成员的类,它实现了 Cloneable 接口并重写了 clone() 方法。在客户端代码中,我们先创建一个原始对象original
,然后分别进行浅复制和深复制。对于浅复制,我们直接调用了super.clone()
方法,之后我们修改浅复制的新对象shallowCopy
的hobbies
列表,添加了一个新的爱好"travel",并打印出原始对象original
的hobbies
列表,可以看到新添加的爱好也被修改了。这是因为浅复制的新对象和原始对象共享同一个hobbies
列表,它们只是拥有了同一个引用而已。
接着,我们对深复制的新对象deepCopy
也添加了一个新的爱好"coding",再次打印出原始对象original
的hobbies
列表,发现它并没有受到影响。这是因为深复制的新对象拥有了一个全新的hobbies
列表,它与原始对象的列表是完全独立的。
因此,浅复制和深复制的区别在于新对象与原始对象之间是否共享引用类型的数据成员。对于需要独立修改的数据成员,应该使用深复制,否则可能会影响到其他对象。