原型模式
原型模式主要涉及對象的拷貝。之前針對Python語言寫過一篇比較詳細的關於對象賦值、淺拷貝、深拷貝的博客:python對象賦值、淺複製、深複製的區別. 下面就主要寫一下淺拷貝和深拷貝在Java語言中的實現。
Java淺拷貝
Java的淺拷貝通過實現Cloneable
接口並重寫clone
方法來實現,本質上是調用了Object
類的clone
方法由JNI實現了具體類的淺拷貝,用戶無需關心其細節。以下是Person類的淺拷貝的實例代碼。
驅動類:Main.java
package shallow_clone;
public class Main {
public static void main(String[] args) {
Person me = new Person(1, "da_kao_la");
try {
Person you = me.clone();
me.setId(2);
System.out.println(me); // id: 2, name: da_kao_la
System.out.println(you); // id: 1, name: da_kao_la
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}
}
Person.java
package shallow_clone;
public class Person implements Cloneable {
private int id;
private String name;
public int getId() {
return this.id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public Person(int id, String name) {
this.id = id;
this.name = name;
}
@Override
protected Person clone() throws CloneNotSupportedException {
return (Person) super.clone();
}
@Override
public String toString() {
return "id: " + id + ", name: " + name;
}
}
Java深拷貝
Java的深拷貝有兩種方法:
- 當類屬性的引用關係層數不深時,Java的深拷貝可以通過遞歸調用
clone
方法實現 - 利用對象序列化機制的拷貝是一種通用的深拷貝方法,對於任何用戶編寫的類,其深拷貝方法的代碼是固定的
以下演示利用對象序列化機制的深拷貝。
驅動類:Main.java,比較了淺拷貝和深拷貝的差異。
package deep_clone;
public class Main {
public static void main(String[] args) {
Person p1 = new Person(1, "da_kao_la");
Person p2 = new Person(2, "java");
Person p3 = new Person(3, "cpp");
p1.addFriend(p2);
try {
/********** shallow clone **********/
Person p0 = p1.clone();
p0.addFriend(p3);
System.out.println(p1);
// id: 1
// name: da_kao_la
// friends:
// id: 2, name: java
// id: 3, name: cpp
System.out.println(p0);
// id: 1
// name: da_kao_la
// friends:
// id: 2, name: java
// id: 3, name: cpp
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
/********** deep clone **********/
p1 = new Person(1, "da_kao_la");
p1.addFriend(p2);
Person p0 = p1.deepClone();
p0.addFriend(p3);
System.out.println(p1);
// id: 1
// name: da_kao_la
// friends:
// id: 2, name: java
System.out.println(p0);
// id: 1
// name: da_kao_la
// friends:
// id: 2, name: java
// id: 3, name: cpp
}
}
Person.java,其clone
方法和deepClone
方法分別實現了對象的淺拷貝和深拷貝。
package deep_clone;
import java.io.Serializable;
import java.util.ArrayList;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
public class Person implements Cloneable, Serializable {
private static final long serialVersionUID = 1L;
private int id;
private String name;
private ArrayList<Person> friends;
public int getId() {
return this.id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public void addFriend(Person friend) {
this.friends.add(friend);
}
public Person(int id, String name) {
this.id = id;
this.name = name;
this.friends = new ArrayList<>();
}
@Override
protected Person clone() throws CloneNotSupportedException {
return (Person) super.clone();
}
public Person deepClone() {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try {
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(this);
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
return (Person) ois.readObject();
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
return null;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("id: " + this.id + "\n");
sb.append("name: " + this.name + "\n");
sb.append("friends: \n");
for (Person friend: this.friends) {
sb.append("\tid: " + friend.getId() + ", name: " + friend.getName() + "\n");
}
return sb.toString();
}
}