1. 程式人生 > >【設計模式】物件的克隆-原型模式

【設計模式】物件的克隆-原型模式

      原型模式是物件的建立模式。原型模式使用原型例項指定建立物件的型別,通過克隆原型來建立新的物件,其實就是複製物件。

       原型模式在我們的生活中處處都存在,大家應該用過很多軟體,都有模板,就拿我現在用的思維導圖來說,我經常都要做計劃,而這個計劃的大概框架或內容是一樣的,只是某些地方有所不同,所以會把常用的思維導圖儲存為模板,然後每次需要做一個新的計劃的時候就通過模板來建立,然後再進行細節修改。

       雖然我們舉了模板這個例子,但原型模式和模板方法模式是不一樣的,不要混淆了,原型模式是物件的建立模式,模板方法模式是類的行為模式。

       原型模式有兩種表現形式,一種是簡單形式

,另一種是登記形式,它們是原型模式的不同實現。

一、原型模式的簡單形式,該模式有三個角色,具體如下圖所示:


抽象原型類宣告克隆方法的介面,是具體原型類的公共父類,具體原型類實現了抽象原型類的克隆方法。客戶端建立一個原型物件之後,可以通過該物件的克隆方法建立多個相同的物件。

原型模式的核心在於如何實現克隆方法,在java有2種常用方法。

1.    通用實現方法(任何面嚮物件語言都可以用的方法)

class ConcretePrototype implements Prototype{
	private String attr;
	public void setAttr(String attr){
		this.attr = attr;
	}
	public String getAttr(){
		return this.attr;
	}
//克隆方法
	public Prototype clone(){
		Prototype prototype = new ConcretePrototype();
		prototype.setAttr(this.attr);
		return prototype;
	}
}

客戶端建立原型物件和克隆物件程式碼:


Prototype planA = new ConcretePrototype();
plan.setAttr("dailyPlan");
Prototype planB = planA.clone();

2.java語言的clone()方法

       在java中Object類提供了一個clone()方法,但是必須得實現一個介面Cloneable,表示該java類支援被複制,如果沒有實現會丟擲loneNotSupportedException異常。

class ConcretePrototype implements Cloneable{
	...
//克隆方法
	pbulic Prototype clone(){
		Object object = null;
		try{
			object = super.clone();
			return (Prototype)object;
		}catch(CloneNotSupportedException e){
			System.out.println("不支援克隆");
			return null;
		}
	}
}

客戶端建立原型物件和克隆物件的程式碼:

Prototype planA = new ConcretePrototype();
Prototype planB = planA.clone();

二、原型模式的登記形式

       該方法引入了原型管理器,所以包含4個角色,原型管理器角色是負責建立和登記具體原型類物件。類圖如下:

原型管理器定義了一個Hashtable用於儲存原型物件:

class PrototypeManager{
	private Hashtable ht = new Hashtable();
	private static PrototypeManager pm = new PrototypeManager();

	private PrototypeManager(){
	}
	//增加新的原型物件
	public void add(String key,Prototype plan){
		ht.put(key,plan);
	}
	//通過克隆取得新的物件
	public Prototype get(String key){
		return ((Prototype)ht.get(key)).clone();
	}
	public static PrototypeManager getPrototypeManager(){
		return pm;
	}
}

淺克隆與深克隆

1.    在淺克隆中,當物件被複制時只複製它本身和其中的包含的值型別的成員變數,而引用型別的成員變數並沒有被複制。通過覆蓋Object類的clone()方法可以實現淺克隆。

2.    在深克隆中,無論原型物件的成員變數是值型別還是引用型別,都將複製一份給克隆物件。在Java語言中,如果需要實現深克隆,可以通過序列化等方式來實現。序列化就是將物件寫入到流的過程,寫到流中的物件是原有物件的一個複製品,而原有物件任然存在記憶體中。通過序列化實現的複製不僅可以複製物件本身,也能複製其引用的成員物件,因此通過序列化將物件寫到一個流中,再從流中讀出來,可以實現深克隆。

能夠實現序列化的物件類必須實現Serializable介面,否則無法實現序列化。(注意:需要複製的引用物件也需實現Serializable介面

class ConcretePrototype implements Serializable{
	...
	//深克隆
	public Prototype deepClone() throws IOException , ClassNofoundException 
										,OptionalDataException{
		ByteArrayOutputStream bao = new ByteArrayOutputStream();
		ObjectOutputStream oos = new ObjectOutputStream(bao);
		oos.writeObject(this);
		//將物件從流中取出
		ByteArrayInputStream bis = new ByteArrayInputStream(bao.toByteArray());
		ObjectInputStream ois = new ObjectInputStream(bis);
		return (Prototype)ois.readObject();
	}
}


Author:立禮
Sign:人生不要有太多的幻想,而要有更多的行動。