原型模式
原型模式屬於對象的創建模式,通過給出一個原型對象來指明所有創建的對象的類型,然后用復制這個原型對象的辦法創建出更多同類型的對象,這就是原型模式的用意。
原型模式結構
原型模式要求對象實現一個可以克隆機身的接口(關於克隆,請參考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方法,它直接操作內存中的二進制流,特別是復制大對象時,性能的差別非常明顯。
使用原型模式的另一個好處是簡化對象的創建,使得創建對象就像普通的復制黏貼一樣簡單。