原型模式 prototype也是常用的一種設計模式,java中已經內置,藉助於Object的clone方法,本文對原型模式進行了簡單介紹,以及Java實現,並且介紹了對象的深拷貝與淺拷貝。 ...
原型模式 prototype
意圖
用原型實例指定需要創建的對象的類型,然後使用複製這個原型對象的方法創建出更多同類型的對象 顯然,原型模式就是給出一個對象,然後克隆一個或者更多個對象 小時候看過的動畫片《西游記》,主題曲猴哥中有一句“拔一根毫毛 ,吹出猴萬個 ”這就是原型模式 孫悟空作為原型對象,“拔一根毫毛 ,吹” 這就是調用複製對象方法,“猴”萬個,就是結果了,創建了“萬個” 猴子原型模式的根本-拷貝
原型模式的根本在於對象的拷貝 說白了就是:如何複製一個對象? 對象的表示 Object ref = new Object(); 上面這句話可以理解為三個步驟- 創建一個Object類型的引用名為 ref
- 創建了一個Object類型的對象
- 使變數ref指向這個新的對象的記憶體地址
結構
原型模式作為創建型模式的一種 與工廠模式建造者模式是類似的,都是為了創建對象 只不過是創建的方式不同 原型模式的創建邏輯則是藉助於已經存在的對象,調用他的拷貝方法,從而創建相同類型的新的對象 根據依賴倒置原則,面向抽象而不是細節進行編程,所以使用抽象角色Prototype用於描述原型類 一種通用的結構描述形式為: Client 客戶端角色 客戶端程式發起創建對象請求 Prototype 抽象原型角色 抽象角色用於描述原型類,給出具體原型類需要的協議 介面或者抽象類 ConcretePrototype具體原型角色 被覆制的對象類型代碼示例
package prototype; public interface Prototype extends Cloneable { Prototype clone(); }
package prototype; public class ConcreatePrototype implements Prototype { @Override public Prototype clone() { try{ return (Prototype)super.clone(); }catch (CloneNotSupportedException e){ return null; } } }
package prototype; public class Client { public static void main(String[] args){ Prototype prototype = new ConcreatePrototype(); Prototype clonedObj = (Prototype)prototype.clone(); System.out.println(clonedObj.getClass()); System.out.println(prototype == clonedObj); } }
Java天然的原型模式
在Java中,所有的對象都繼承自Java.lang.Object 而 Object中有clone()方法 ,可以將一個對象進行拷貝 所以說Java天生的內置了原型模式---通過對象的clone方法進行對象的拷貝 不過也有一些具體的規則需要註意 Java語言提供了Cloneable介面,作為標記介面 凡是實現了Cloneable介面的類都聲稱:“可以安全的在這個類上使用clone()方法”。 試圖調用clone()方法時,如果此對象的類沒有實現 Cloneable 介面,則會拋出 CloneNotSupportedException。 clone()方法如下 clone方法是淺拷貝而不是深拷貝 Object中的clone()方法規定了拷貝的一般協議,可以參看API文檔- 對於任何對象 x,表達式:x.clone() != x,克隆對象與原始對象不是同一個對象
- x.clone().getClass() == x.getClass() ,克隆對象與原始對象是同一種類型
- x.clone().equals(x) 為true
- 實現Cloneable介面
- 覆蓋或者使用繼承而來的clone()方法
擁有管理器的原型模式
原型模式中最為關鍵的是調用某個對象的拷貝方法,進行原始對象的複製 所以原型模式一種常見的用法就是藉助於這個"原始對象",達到工廠方法的效果 客戶端中保存一個ConcretePrototype類型的對象 後續的對象創建獲取就是客戶端通過這個內部的對象,調用它的拷貝方法進行進一步的操作 如果產品結構比較簡單,可能只需要幾種類型的對象即可 上面的原型結構比較適合,客戶端自己保存所有的對象 但是 如果產品等級結構比較雜亂,或者說要創建的原型對象是數目並不是固定的 又可以進一步將管理對象的職責進行提取分離,抽象出來一個管理器的角色 專門用於管理這些對象 這種帶管理器的原型模式中,客戶端就不在持有原型對象的引用了,也就是客戶端不在擁有原型對象 取而代之的是通過管理器獲取 Client 客戶端角色 向管理員發起創建對象的請求 Prototype、ConcretePrototype 角色與之前的概念相同 PrototypeManager 角色 原型管理器角色,負責原型對象的創建和管理示例代碼
在原來的基礎上增加原型管理器package prototype; import java.util.HashMap; public class PrototypeManager { /*hashMap維護原型對象 * */ private HashMap<String,Object> map = new HashMap<>(); /*餓漢式單例模式返回創建原型對象管理器 邏輯上原型對象管理器只有一個 * */ private static PrototypeManager prototypeManager= new PrototypeManager(); public static PrototypeManager getPm(){ return prototypeManager; } /*初始化內置兩個原型對象 * */ private PrototypeManager(){ map.put("product1",new ConcreatePrototype()); map.put("product2",new ConcreatePrototype()); } /*提供了添加原型對象方法*/ public void add(String key,Prototype prototype){ map.put(key,prototype); } /*提供了獲取對象的方法,獲取的對象依賴的是clone,而不是保存進去的對象*/ public Prototype get(String key){ return ((Prototype)map.get(key)).clone(); } }測試類Client角色中也增加相關代碼 看得出來,從對象管理器中獲取的對象,都是原有對象的一個clone 並不是相同的對象 帶管理器的原型模式也叫做 登記形式的原型模式 登記就是相當於在管理器中備案