原型模式(Prototype),用原型實例指定創建對象的種類,并且通過拷貝這些原型創建新的對象。
原型模式其實就是從一個對象再創建另外一個可定制的對象,而不需要知道任何創建的細節。
原型模式主要涉及2個部分:
- 原型類:聲明一個克隆自身的接口。
- 具體原型類:實現一個克隆自身的操作。
Object 類的有一個 clone 方法,該方法的作用是返回一個對象的拷貝,我們需要對它進行重寫,如果想在外部訪問,還需要將該方法的 protected 修飾符改為 public。
使用 Object 類的 clone 方法還需要添加對 Cloneable 接口的實現,否則會拋不支持克隆的異常。java 的基礎類庫中提供 Cloneable 接口是一個標記接口,接口內部沒有任何代碼,它會在運行時通知虛擬機可以安全地在實現了此接口的類上使用 clone 方法。
以學生類為例,在學生類中重寫了 Object 類的 clone 方法,用以對學生對象進行克隆。
- 學生類
public class Student implements Cloneable {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public void display() {
System.out.println("name: " + name + ", age: " + age);
}
public Object clone() {
try {
return super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
return null;
}
}
}
- 客戶端測試類
public class Client {
public static void main(String[] args) {
Student liLei = new Student();
liLei.setName("Li Lei");
liLei.setAge(14);
Student hanMeiMei = (Student)liLei.clone();
hanMeiMei.setName("Han Mei Mei");
liLei.display();
hanMeiMei.display();
}
}
運行結果:
name: Li Lei, age: 14
name: Han Mei Mei, age: 14
上面完成了對學生對象的一個克隆,從李雷克隆出了韓梅梅。
由于 Object 類的 clone 方法是一個本地方法,它直接對內存中的二進制進行操作,所以使用原型模式創建對象的性能要優于直接 new 一個對象。特別是在循環次數多或者對象創建相對復雜的情況下,可以考慮原型模式的使用。
克隆還涉及到淺復制和深復制的問題,由于這里學生類的姓名和年齡都是基本類型,這是淺復制。如果存在引用類型,那么淺復制就只能復制一個引用但不能復制引用的對象,就會造成原始對象和副本引用同一個對象的問題。要解決這個問題就需要用到深復制了,深復制會逐層進行復制。