2010年11月7日 星期日

[OO 設計模式] Prototype Patterns : 原型模式 - 從物件建立另一個可定製物件且不需要知道建立細節


前言 :
轉載自 這裡
有些物件若以標準的方式建立實例,或者是設定至某個狀態需要複雜的運算及昂貴的資源,則您可以考慮直接以某個物件作為原型,在需要個別該物件時,複製原型並傳回。

請注意,在這邊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):
  1. package ch09.car;  
  2.   
  3. import java.util.*;  
  4.   
  5. class Wheel implements Cloneable{  
  6.     public Wheel(){  
  7.         System.out.println("Wheel constructor is called!");  
  8.     };  
  9.      // 也許還有一些複雜的設定  
  10.     protected Object clone() throws CloneNotSupportedException {   
  11.         return super.clone();   
  12.     }   
  13. }  
  14.   
  15. class Car implements Cloneable{  
  16.     private String name="Unknown";  
  17.       
  18.     public Car(){  
  19.         System.out.println("Car constructor is called!");  
  20.     }  
  21.     public Car(String n) {  
  22.         name = n;  
  23.         System.out.printf("Car:%s constructor is called!\n", n);  
  24.     }  
  25.     // 也許還有一些複雜的設定  
  26.     private Wheel[] wheels = {new Wheel(), new Wheel(), new Wheel(), new Wheel()};  
  27.       
  28.     protected Object clone() throws CloneNotSupportedException {  
  29.         Car copy = (Car) super.clone();  
  30.         copy.wheels = (Wheel[]) this.wheels.clone();  
  31.         for(int i = 0; i < this.wheels.length; i++) {  
  32.             copy.wheels[i] = (Wheel) this.wheels[i].clone();  
  33.         }  
  34.         return copy;   
  35.     }  
  36.       
  37.     public String getName(){  
  38.         return name;  
  39.     }  
  40. }  
  41.   
  42. class Cars {  
  43.     private Map prototypes = new HashMap();  
  44.     void addPrototype(String brand, Car prototype) {  
  45.         prototypes.put(brand, prototype);  
  46.     }  
  47.     Car getPrototype(String brand) throws CloneNotSupportedException {  
  48.         return (Car) prototypes.get(brand).clone();  
  49.     }  
  50. }  
  51.   
  52. public class Main {  
  53.     public static void main(String[] args) throws Exception {  
  54.         Car bmw = new Car("BMW");  
  55.         // 作一些 BMW 複雜的初始、設定、有的沒的  
  56.         Car benz = new Car("BENZ");  
  57.         // 作一些 BENZ 複雜的初始、設定、有的沒的  
  58.         Cars cars = new Cars();  
  59.         cars.addPrototype("BMW", bmw);  
  60.         cars.addPrototype("BENS", benz);  
  61.         // 取得 BMW 原型複製, Constructor 不會被呼叫.  
  62.         System.out.println("\t>>>Clone Car Type:BMW");  
  63.         Car bmwPrototype = cars.getPrototype("BMW");  
  64.         System.out.printf("Prototype Car(%s)\n", bmwPrototype.getName());  
  65.     }  
  66. }  
執行結果 :
Wheel constructor is called!
Wheel constructor is called!
Wheel constructor is called!
Wheel constructor is called!
Car:BMW constructor is called!
Wheel constructor is called!
Wheel constructor is called!
Wheel constructor is called!
Wheel constructor is called!
Car:BENZ constructor is called!
>>>Clone Car Type:BMW <執行Clone 時,物件的Constructor 不會被執行 >
Prototype Car(BMW)

補充說明 :
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.
This message was edited 8 times. Last update was at 17/05/2010 13:32:35

沒有留言:

張貼留言

[Git 常見問題] error: The following untracked working tree files would be overwritten by merge

  Source From  Here 方案1: // x -----删除忽略文件已经对 git 来说不识别的文件 // d -----删除未被添加到 git 的路径中的文件 // f -----强制运行 #   git clean -d -fx 方案2: 今天在服务器上  gi...