原型模式
原型模式屬於物件的建立模式,通過給出一個原型物件來指明所有建立的物件的型別,然後用複製這個原型物件的辦法建立出更多同型別的物件,這就是原型模式的用意。
原型模式結構
原型模式要求物件實現一個可以克隆機身的介面(關於克隆,請參考Cloneable介面和Object的clone()方法),這樣就可以通過複製一個例項物件本身來建立一個新的例項。這樣一來,通過原型例項建立新的物件,就不再需要關心這個例項本身的型別,只要實現了克隆自身的方法,就可以通過這個方法來獲取新的物件,而無須再通過new去建立。
原型模式涉及到三個角色:
1、客戶角色
客戶類提出建立物件的請求
2、抽象原型角色
這是一個抽象角色,通常由一個介面或者抽象類實現,此角色給出所有具體原型類所需的介面
3、具體原型角色
被複制的角色,此角色需要實現抽象的原型角色所要求的介面
原型模式示例
定義一個抽象原型角色,抽象類,實現Cloneable介面:
public abstract class Prototype implements Cloneable { public Prototype clone() { Prototype prototype = null; try { prototype = (Prototype)super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return prototype; } public abstract void show(); }
定義一個具體原型角色,繼承Prototype類:
public class ConcretePrototype extends Prototype { public void show() { System.out.println("ConcretePrototype.show()"); } }
定義一個客戶端呼叫:
public class Client { public static void main(String[] args) { ConcretePrototype cp = new ConcretePrototype(); for (int i = 0; i < 10; i++) { ConcretePrototype clonecp = (ConcretePrototype)cp.clone(); clonecp.show(); } } }
比方說一個類例項很有用的時候,就可以使用原型模式去複製它。不過原型模式單獨用得不多,一般是和其他設計模式一起使用。
原型模式在Java中的應用及解讀
既然原型模式的關注點是在於通過克隆自身來獲取一個和自身一樣的物件,那其實只要是實現了Cloneable介面的類都可以算是原型模式的應用,比如ArrayList吧:
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable { ... public Object clone() { try { ArrayList<E> v = (ArrayList<E>) super.clone(); v.elementData = Arrays.copyOf(elementData, size); v.modCount = 0; return v; } catch (CloneNotSupportedException e) { // this shouldn't happen, since we are Cloneable throw new InternalError(); } } ... }
程式中獲取到了一個ArrayList的例項arrayList,我們完全可以通過呼叫arrayList.clone()方法獲取到原ArrayList的拷貝。
原型模式的優點
原型模式是一種類的建立模式,可以看到到目前為止的四種建立型模式,客戶端(呼叫方)都沒有直接new一個類例項出來。把new一個類例項的動作由客戶端(呼叫方)交給別人做而不是自己做,這就是建立型模式的宗旨。
使用原型模式建立物件比直接new一個物件在效能上好得多,因為Object類的clone()方法是一個native方法,它直接操作記憶體中的二進位制流,特別是複製大物件時,效能的差別非常明顯。
使用原型模式的另一個好處是簡化物件的建立,使得建立物件就像普通的複製黏貼一樣簡單。