I. 原型模式的定義
原型(Prototype)模式的定義如下:用一個(gè)已經(jīng)創(chuàng)建的實(shí)例作為原型,通過(guò)復(fù)制該原型對(duì)象來(lái)創(chuàng)建一個(gè)和原型相同或相似的新對(duì)象。在這里,原型實(shí)例指定了要?jiǎng)?chuàng)建的對(duì)象的種類(lèi)。用這種方式創(chuàng)建對(duì)象非常高效,根本無(wú)須知道對(duì)象創(chuàng)建的細(xì)節(jié)。
II. 原型模式的應(yīng)用場(chǎng)景
- 對(duì)象之間相同或相似,即只是個(gè)別的幾個(gè)屬性不同的時(shí)候。
- 創(chuàng)建對(duì)象成本較大,例如初始化時(shí)間長(zhǎng),占用CPU太多,或者占用網(wǎng)絡(luò)資源太多等,需要優(yōu)化資源。
- 創(chuàng)建一個(gè)對(duì)象需要繁瑣的數(shù)據(jù)準(zhǔn)備或訪問(wèn)權(quán)限等,需要提高性能或者提高安全性。
- 系統(tǒng)中大量使用該類(lèi)對(duì)象,且各個(gè)調(diào)用者都需要給它的屬性重新賦值。
III. 最簡(jiǎn)單的原型模式
- 給bean類(lèi)實(shí)現(xiàn)Cloneable接口并實(shí)現(xiàn)clone方法 (該方式屬于淺拷貝)
public class Sheep implements Cloneable{
private String name;
private Integer age;
/* 省略get/set/constructor */
@Override
protected Object clone(){
Sheep sheep = null;
try {
sheep = (Sheep) super.clone();
} catch (Exception e) {
e.printStackTrace();
}
return sheep;
}
}
IV. 淺拷貝與深拷貝
- 淺拷貝 : 創(chuàng)建一個(gè)新對(duì)象,新對(duì)象的屬性和原來(lái)對(duì)象完全相同,對(duì)于非基本類(lèi)型屬性,仍指向原有屬性所指向的對(duì)象的內(nèi)存地址。[ 比如sheep類(lèi)中添加一個(gè)Sheep friend 屬性,copy后,sheep1與sheep指向的friend是同一個(gè)地址,此時(shí)調(diào)用sheep.friend.setName(),sheep1中的值也會(huì)改變]
- 深拷貝 : 創(chuàng)建一個(gè)新對(duì)象,屬性中引用的其他對(duì)象也會(huì)被克隆,不再指向原有對(duì)象地址。
V. 深拷貝的兩種實(shí)現(xiàn)
1. 首先準(zhǔn)備這樣2個(gè)類(lèi),均實(shí)現(xiàn)Serializable & Cloneable

示例類(lèi)UML
方式一 : 對(duì)引用類(lèi)型逐個(gè)處理 (不推薦使用)
@Override
protected Object clone() {
DeepCopy deep = null;
try {
deep = (DeepCopy) super.clone();
DeepCopyInner deepCopyInner = (DeepCopyInner) deep.getDeepCopyInner().clone();
deep.setDeepCopyInner(deepCopyInner);
} catch (Exception e) {
e.printStackTrace();
}
return deep;
}
方式二 : 將整個(gè)對(duì)象序列化 (推薦使用)
@Override
protected Object clone() {
ByteArrayOutputStream bos = null;
ObjectOutputStream oos = null;
ByteArrayInputStream bis = null;
ObjectInputStream ois = null;
try {
// 序列化
bos = new ByteArrayOutputStream();
oos = new ObjectOutputStream(bos);
oos.writeObject(this); // 將當(dāng)前對(duì)象以對(duì)象流的方式輸出
// 反序列化
bis = new ByteArrayInputStream(bos.toByteArray()); // 將oos的輸出讀入
ois = new ObjectInputStream(bis);
DeepCopy deep = (DeepCopy) ois.readObject();
return deep;
} catch (Exception e) {
e.printStackTrace();
// 出現(xiàn)異常返回null
return null;
} finally {
close(bos, oos, bis, ois);
}
}
// 關(guān)閉
private void close(ByteArrayOutputStream bos, ObjectOutputStream oos, ByteArrayInputStream bis, ObjectInputStream ois){
try {
bos.close();
oos.close();
bis.close();
ois.close();
} catch (Exception e) {
e.printStackTrace();
}
}
VI. 總結(jié)
優(yōu)點(diǎn):
- 克隆對(duì)象比new一個(gè)對(duì)象的速度更快,開(kāi)銷(xiāo)更少
- 可以使用深拷貝保存對(duì)象在某一時(shí)刻的狀態(tài),方便撤銷(xiāo)操作
缺點(diǎn):
- 需要為每個(gè)類(lèi)配置clone方法
- clone 方法位于類(lèi)的內(nèi)部,當(dāng)對(duì)已有類(lèi)進(jìn)行改造的時(shí)候,需要修改代碼,違背了開(kāi)閉原則。