原型模式是指通過拷貝原型對象創建新的對象,它在23種設計模式中相對來說簡單一些。
原型模式的核心在於拷貝原型對象,JDK的實現拷貝的方式是直接基於內存二進制流進行拷貝,無需再經歷耗時的對象初始化過程,性能提升很多。
拷貝的目的是避免複雜的屬性賦值和耗時的對象構建。下面來看原型模式的類結構圖
從上面的UML圖中,我們可以發現原型模式主要包含3個角色:
- 客戶(Client):客戶類提出創建對象的請求
- 抽象原型(ProtoType):規定拷貝接口
- 原型實現類:(ConcreteProtoType):能被拷貝的對象
相信大家,曾經看到過下面的代碼:
這樣的代碼雖然工整,命名也規範,註釋可能寫的也全面。這就是原型模式的產生的需求場景。它能幫我解決什麼問題呢?
原型模式的需求場景:
1、類初始化消耗資源較多
2、new 產生的一個對象需要繁瑣的過程(數據準備,權限訪問等)
3、構造函數複雜
4、循環體中產生大量對象時
在 Spring 框架中,原型模式應用非常廣泛。例如 scope = "prototype" ,在我們經常用的JSON.parseObject() 也是一種原型模式。
原型模式的Java實現方式可以分2種:淺拷貝和深拷貝。
淺拷貝
<code>@Data
public class User implements Cloneable {
private int age;
private String name;
private List<string> hobbies;
@override
public User clone(){
try {
return (User)super.clone();
} catch (Exception e) {
//TODO: handle exception
return null;
}
}
}/<string>/<code>
通過實現Cloneable接口的Clone() 方法得到拷貝類,改變原型對象age,String值,拷貝對象不會跟著改變,相互獨立。但是細心的朋友會發現,調用原型對象hobbies.add()方法添加新元素,拷貝對象的hobbies也會跟著變化。這是為什麼呢? 這是因為List<string>屬於引用類型成員變量,雖然拷貝形成了新的變量,但是指向的還是內存推中的原List對象。/<string>
深拷貝
<code>@Data
public class User implements Cloneable {
private int age;
private String name;
private List<string> hobbies;
@override
public User clone(){
try {
return (User)super.clone();
} catch (Exception e) {
//TODO: handle exception
return null;
}
}
//clone接口
public User DeepClone(){
try {
User newUser = this.clone();
newUser.hobbies = (List)((ArrayList)newUser.hobbies).clone();
rerurn newUser;
} catch (Exception e) {
//TODO: handle exception
}
}
//反序列化
public User DeepClone2(){
try {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeeObject(this);
ByteArraryInputStream bis = new ByteArraryInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
return (User)ois.readObject();
} catch (Exception e) {
//TODO: handle exception
}
}
}/<string>/<code>
有興趣的朋友可以分別測試deepClone() 和 deepClone2() 方法,都可以實現深度克隆。
通過反序列化可以實現對象深度克隆這個很容易理解。但是對ArrayLis<string>變量做clone(),為什麼也能實現深度克隆,我們看一下ArrayList源代碼自然就明白了。/<string>
我們發現ArrayList遍歷了所有元素,被進行了copy。
總結原型模式
優點:
1、java自帶原型模式基於內存二進制流拷貝,比直接new一個對象性能提升很多
2、可以使用深度克隆保存對象的狀態,簡化創建對象的過程
缺點:
1、需要為每個類配置克隆方法
2、克隆方法位於類的內部,修改代碼違背開閉原則
閱讀更多 福星沐浴露 的文章