轉載自 這裡
有些物件若以標準的方式建立實例,或者是設定至某個狀態需要複雜的運算及昂貴的資源,則您可以考慮直接以某個物件作為原型,在需要個別該物件時,複製原型並傳回.
先來看看Prototype的類別圖 :
請注意,在這邊Cloneable並非指Java中的 java.lang.Cloneable,而是指支援原型複製的物件,必須實作之公開協定.
不 同的語言可能提供不同程度支援之物件複製技術,以Java而言,java.lang.Object本身即定義有clone()方法,因此所有的物件基本上 皆具自我複製之能力,不過真正要讓物件支援複製,則物件必須實作java.lang.Cloneable這個標示介面(Tag interface).
下面這個範例示範了,如何使用Java實作Prototype模式(建議您參考:How to avoid traps and correctly override methods from java.lang.Object):
- Car.java :
- package dp.prototype;
-
- public class Car implements Cloneable{
-
- private Wheel[] wheels;
-
- public Car(){
-
- System.out.println("Car constructor: Initialization...");
- try {
- Thread.sleep(1000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- wheels = new Wheel[4];
- for(int i=0; i<4; i++) wheels[i] = new Wheel();
- }
-
- protected Object clone() throws CloneNotSupportedException {
- Car copy = (Car) super.clone();
- copy.wheels = (Wheel[]) this.wheels.clone();
- for(int i = 0; i < this.wheels.length; i++) {
- copy.wheels[i] = (Wheel) this.wheels[i].clone();
- }
- return copy;
- }
-
- }
- Wheel.java :
- package dp.prototype;
-
- public class Wheel implements Cloneable{
- public Wheel(){
-
- System.out.println("Wheel Constructor: Initialization...");
- try {
- Thread.sleep(500);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- protected Object clone() throws CloneNotSupportedException {
- return super.clone();
- }
- }
- Cars.java :
- package dp.prototype;
-
- import java.util.HashMap;
- import java.util.Map;
-
- public class Cars {
- private Map prototypes = new HashMap();
- void addPrototype(String brand, Car prototype) {
- prototypes.put(brand, prototype);
- }
- Car getPrototype(String brand) throws CloneNotSupportedException {
- return (Car) prototypes.get(brand).clone();
- }
- }
- Main.java :
- package dp.prototype;
-
- public class Main {
- public static void main(String[] args) throws CloneNotSupportedException{
- long bmwST = System.currentTimeMillis();
- System.out.println("Create BMW...");
- Car bmw = new Car();
- System.out.println("taking "+(System.currentTimeMillis()-bmwST)/1000+" sec\n");
-
-
- long benzST = System.currentTimeMillis();
- System.out.print("Create Benz...");
- Car benz = new Car();
- System.out.println("taking "+(System.currentTimeMillis()-benzST)/1000+" sec\n");
-
- Cars cars = new Cars();
-
-
- cars.addPrototype("BMW", bmw);
- cars.addPrototype("BENS", benz);
-
-
- long protoST = System.currentTimeMillis();
- System.out.println("Take Prototype of BMW...");
- Car bmwPrototype = cars.getPrototype("BMW");
- System.out.println("taking "+(System.currentTimeMillis()-protoST)+" ms\n");
- }
- }
執行結果 :
Create BMW...
Car constructor: Initialization...
Wheel Constructor: Initialization...
Wheel Constructor: Initialization...
Wheel Constructor: Initialization...
Wheel Constructor: Initialization...
taking 3 sec
Create Benz...Car constructor: Initialization...
Wheel Constructor: Initialization...
Wheel Constructor: Initialization...
Wheel Constructor: Initialization...
Wheel Constructor: Initialization...
taking 3 sec
Take Prototype of BMW...
taking 0 ms // 由輸出結果可以知道透過 prototype 可以省掉Constructor 的 Initialization 時間...
Prototype模式可應用於避免子類化物件創建者(object creator),在 Gof 的設計模式書中有個範例,設計一個通用的圖型編輯器框架。在這個框架中有個工具列,您可以在上面選擇符號以加入圖片中,並可以隨時調整符號的位置等。
圖型編輯器框架是通用的,然而事先並不知道這些符號的型態,有人或許會想到繼承圖型編輯器框架來為每個符號設計一個框 架子類別,但由於符號的可能種類很多,這會產生相當多的子類別,為了避免這種情況,可以透過Prototype模式來減少子類別的數目,可以設計出以下的 結構.
依照這個結構,圖型編輯器框架可以獨立於要套用的符號類別,雖然不知道被複製傳回的物件型態是什麼,但可以用原型複製的方式來建立新物件,且可以按照 Graphics所定義的公開介面來操作這些物件,例如使用範例中的draw()方法來繪製符號.
補充說明 :
* Wiki : Prototype Pattern
The prototype pattern is a creational design pattern used in software development when the type of objects to create is determined by a prototypical instance, which is cloned to produce new objects. This pattern is used to:
-
avoid subclasses of an object creator in the client application, like the
abstract factory pattern does.
-
avoid the inherent cost of creating a new object in the standard way (e.g., using the 'new' keyword) when it is prohibitively expensive for a given application.
To implement the pattern, declare an abstract base class that specifies a pure virtual clone() method. Any class that needs a "polymorphic constructor" capability derives itself from the abstract base class, and implements the clone() operation.
沒有留言:
張貼留言