孫悟空可以用猴毛複製出很多跟自己長得一模一樣的分身。在設計模式中也存在一個類似的模式,可以透過一個原型物件克隆出多個一模一樣的物件,該模式被稱為原型模式。
一、原型模式
1. 定義:使用原型例項指定建立物件的種類,並且透過克隆這些原型建立新的物件。原型模式是一種物件建立型模式。
2. 工作原理:將一個原型物件傳給要發動建立的物件,這個要發動建立的物件透過請求原型物件克隆自己來實現建立過程。
透過克隆方法所建立的物件是全新的物件,它們在記憶體中擁有新的地址。通常,對克隆所產生的物件進行的修改不會對原型物件造成任何影響,每個克隆對都是相互獨立的。透過不同的方式對克隆物件進行修改後,可以得到一系列相似但不完全相同的物件。
- Prototype(抽象原型類):它是宣告克隆方法的介面,是所有具體原型類的公共父類,可以是抽象類也可以是介面,甚至還可以是具體實現類。
- ConcretePrototype(具體原型類):它實現在抽象原型類中宣告的克隆方法,在克隆方法中返回自己的一個克隆物件。
- Client(客戶類):讓一個原型物件克隆自身從而建立一個新的物件,在客戶類中只需要直接例項化或透過工廠方法等方式建立一個原型物件,再透過呼叫該物件的克隆方法即可得到多個相同的物件。由於客戶類針對抽象原型類Prototype程式設計,因此使用者可以根據需要選擇具體原型類,系統具有較好的可擴充套件性,增加或更換具體原型類都很方便。
原型模式的核心在於如何實現克隆方法。通用的克隆實現方法是在具體原型類的克隆方法中例項化一個與自身型別相同的物件並將其返回,並將相關的引數傳入新建立的物件中,保證它們的成員變數相同。
在客戶類中,只需要建立一個ConcretePrototype物件作為原型物件,然後呼叫其clone方法即可得到對應的克隆物件:
二、原型模型中的深克隆和淺克隆
資料型別:
- 值型別:int、double、byte、boolean、char等簡單資料型別;
- 引用型別:類、介面、陣列等複雜型別。
淺克隆:如果原型物件的成員變數是值型別,將複製一份給克隆物件;如果原型物件的成員變數是引用型別,則將引用物件的地址複製一份給克隆物件,也就是說原型物件和克隆物件的成員變數指向相同的記憶體地址。簡單來說,在淺克隆中,當物件被複制時只複製他本身和其中包含的值型別的成員變數,而引用型別的成員物件並沒有被複制。
深克隆:在深克隆中,無論原型物件的成員變數是值型別還是引用型別,都將複製一份給克隆物件,深克隆將原型物件的所有引用物件也複製一份給克隆物件。簡單來說,在深克隆中,除了物件本身被複制外,物件所包含的所有成員變數也將被複制。
三、原型管理器
原型管理器是將多個原型物件儲存在一個集合中供客戶端使用,它是一個專門複製克隆物件的工程,其中定義了一個集合用於儲存原型物件,如果需要某個原型物件的一個克隆,可以透過複製集合對應的原型物件來獲得。
舉例:根據使用者的請求生成不同的報告。
四、優缺點
優點:
1. 當建立新的物件例項較為複雜時,使用原型模式可以簡化物件的建立過程,透過複製一個已有例項可以提高新例項的建立效率。
2. 擴充套件性較好。由於在原型模式中提供了抽象原型類,在客戶端可以針對抽象原型類進行程式設計,而將具體原型類寫在配置檔案中,增加或減少具體原型類對原有系統都沒有任何影響。
3. 可以使用深克隆的方式儲存物件的狀態。使用原型模式將物件複製一份並將其狀態儲存起來,也可輔助實現撤銷操作。
缺點:
1. 需要為每一個類配備一個克隆方法,而且該克隆方法位於一個類的內部,當對已有的類進行改造時,需要修改原始碼,違背了開閉原則。
2. 在實現深克隆的時候需要編寫較為複雜的程式碼,而且當物件之間存在多重的前提引用時,為了實現深克隆,每一層物件對應的類都必須支援深克隆,實現起來比較麻煩。