原型模式
定義
是指原型執行個體指定建立對象的種類,并且通過拷貝這些原型建立新的對象
調用者不需要知道建立細節,不調用建構函數
屬于建立型模式
原型模式的核心在于拷貝原型對象。以系統中已經存在的一個對象為原型,直接基于記憶體二進制流進行拷貝,無需在經曆耗時的對象初始化過程(不調用構造函數),性能提升許多。當對象的建構比較耗時時,可以利用目前系統中已經存在的對象作為原型,對其進行克隆,進而躲避初始化過程,使得新對象的建立時間大大較少。
适用場景
1. 類初始化小号資源較多
2. new産生一個對象需要非常繁瑣的過程(資料準備,通路權限等)
3. 構造函數比較複雜
4. 循環體中生産大量對象
原型模式的通用寫法
public interface IPrototype<T> {
T clone();
}
public class ConcretePrototype implements IPrototype{
private int age;
private String name;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public ConcretePrototype clone() {
// ConcretePrototype concretePrototype = new ConcretePrototype();
// concretePrototype.setAge(this.age);
// concretePrototype.setName(this.name);
// return concretePrototype;
try {
return (ConcretePrototype) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
return null;
}
}
}
public class BeanUtils {
public static Object copy(Object prototype) {
Class clazz = prototype.getClass();
Object returnValue = null;
try {
returnValue = clazz.newInstance();
for (Field field : clazz.getDeclaredFields()) {
field.setAccessible(true);
field.set(returnValue, field.get(prototype));
}
} catch (Exception e) {
e.printStackTrace();
}
return returnValue;
}
}
通過反射調用原型中的屬性,指派到新的對象中。
原型模式之淺克隆
Cloneable接口:cloneable其實就是一個标記接口,隻有實作這個接口後,然後在類中重寫Object中的clone方法,然後通過類調用clone方法才能克隆成功,如果不實作這個接口,則會抛出CloneNotSupportedException(克隆不被支援)異常
public class ConcretePrototype implements Cloneable{
private int age;
private String name;
private List<String> hobbies;
@Override
public ConcretePrototype clone() {
try {
return (ConcretePrototype) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
return null;
}
}
}
clone方法并不是把原型對象的引用指派為克隆對象,而是在堆中重新開辟空間,将原型對象複制過去,将新的位址傳回給克隆對象。但是對于原型對象中的引用對象,複制到克隆對象中的仍然是對象的引用,其對象不會發生改變。
原型模式之深克隆
深克隆的實作友兩種方式:
1. 序列化
2. json
public class ConcretePrototype implements Cloneable, Serializable {
private int age;
private String name;
private List<String> hobbies;
public ConcretePrototype 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 (ConcretePrototype) ois.readObject();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
優點
- 性能優良,Java自帶的原型模式是基于二進制流的拷貝,比直接new一個對象性能上提升很多
- 可以使用深克隆方式儲存對象的狀态,使用原型模式将對象複制一份并将其狀态儲存,簡化了建立對象的過程,以便需要的時候使用(例如恢複到曆史某一狀态),可以輔助實作撤銷操作
缺點
- 需要為每一個類配置一個克隆方法
- 克隆方法位于類的内部,當對已有的類進行改造的時候,需要修改代碼,違反開閉原則。
- 在實作深克隆時需要編寫較為複雜的代碼,而且當對象之間存在多重嵌套應用時,為了實作深克隆,每一層對象對應的類都必須支援深克隆,實作比較麻煩。