--- tags: Creational Patterns --- # 原型模式 Prototype ## 大綱 有時候建立新的物件很高,如:讀取一次資料庫。 ## 角色 **Prototype**: like the Graphic 宣告自我複製的介面。 **ConcretePrototype**: 具體實作出自我複製的方法。 like the Staff, WholeNote, HalfNote **Client**:叫原型個體自我複製一份,以生出新的物件。 ![](https://i.imgur.com/1WMtSpR.png) Client呼叫Prototype,或是進行註冊/刪除元件的動作 ## 好處 * 將ConcreteProduct類別隱藏起來,減少Client所能知道的類別種類,也能不修改Client即可與其他應用領域的類別協同運作。 * 在執行期增刪成品物件類型:只要向Client註冊Prototype,就能引進新的成品物件類型,且Client可以在執行期安裝或卸除Prototype。 * 改變內容以訂出新的物件:可透過物件複合方式制定新的行為(如:指定物件的個體變數內容)。 * 改變結構以訂出新的物件:將小電路當原型個體,拿到電路元件上擺著。只要複合電路物件的clone()方法採取deep copy,就能將各種不同的電路結構視為原型個體來用。 * 減少子類別數量:不像 Factory Method Pattern 會產生與成品物件類別階層平行對應的Creator類別階層,只要複製原型個體即可。 ## 壞處 * 每一個Prototype子類別都必須實作clone()方法,若是想把clone()加到早已存在的類別裡,或是類別裡有不支援複製動作的物件,或是有循環指涉(circular reference)的情形,就更不容易製作clone()。 ## 雛型範例 ```java= //必須實作Cloneable且必須擲出錯誤訊息 public interface Prototype extends Cloneable { public void getName(); public Prototype clone() throws CloneNotSupportedException; } //所有try-catch皆為必須 public class ConcretePrototype implements Prototype{ public Prototype clone(){ try { return (Prototype) super.clone(); } catch(CloneNotSupportedException e) { e.printStackTrace(); } return null; } } ``` ## 形狀範例 ```java= //Cloneable是java的預設介面 public abstract class Shape implements Cloneable { private String id; protected String type; abstract void draw(); public String getType(){ return type; } public String getId() { return id; } public void setId(String id) { this.id = id; } public Object clone() { Object clone = null; try { clone = super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return clone; } } public class Rectangle extends Shape { public Rectangle(){ type = "Rectangle"; } @Override public void draw() { System.out.println("Inside Rectangle::draw() method."); } } public class Square extends Shape { public Square(){ type = "Square"; } @Override public void draw() { System.out.println("Inside Square::draw() method."); } } public class Circle extends Shape { public Circle(){ type = "Circle"; } @Override public void draw() { System.out.println("Inside Circle::draw() method."); } } //client public class ShapeCache { //紀錄註冊class list private static Hashtable<String, Shape> shapeMap = new Hashtable<String, Shape>(); public static Shape getShape(String shapeId) { Shape cachedShape = shapeMap.get(shapeId); return (Shape) cachedShape.clone(); } // for each shape run database query and create shape // shapeMap.put(shapeKey, shape); // for example, we are adding three shapes public static void loadCache() { Circle circle = new Circle(); circle.setId("1"); shapeMap.put(circle.getId(),circle); Square square = new Square(); square.setId("2"); shapeMap.put(square.getId(),square); Rectangle rectangle = new Rectangle(); rectangle.setId("3"); shapeMap.put(rectangle.getId(), rectangle); } } public class PrototypePatternDemo { public static void main(String[] args) { ShapeCache.loadCache(); Shape clonedShape = (Shape) ShapeCache.getShape("1"); System.out.println("Shape : " + clonedShape.getType()); Shape clonedShape2 = (Shape) ShapeCache.getShape("2"); System.out.println("Shape : " + clonedShape2.getType()); Shape clonedShape3 = (Shape) ShapeCache.getShape("3"); System.out.println("Shape : " + clonedShape3.getType()); } } ``` ## 字形外觀範例 ```java= //Client public class Manager { private Hashtable showcase = new Hashtable(); public void register(String name, Product proto) { showcase.put(name, proto); } public Product create(String protoname) { Product p = (Product)showcase.get(protoname); return p.createClone(); } } //Prototype public interface Product extends Cloneable { public abstract void use(String s); public abstract Product createClone(); } //ConcreteProduct public class UnderlinePen implements Product { private char ulchar; public UnderlinePen(char ulchar) { this.ulchar = ulchar; } public void use(String s) { int length = s.getBytes().length; System.out.println("\"" + s + "\""); System.out.print(" "); for (int i = 0; i < length; i++) { System.out.print(ulchar); } System.out.println(""); } public Product createClone() { Product p = null; try { p = (Product)clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return p; } } public class MessageBox implements Product { private char decochar; public MessageBox(char decochar) { this.decochar = decochar; } public void use(String s) { int length = s.getBytes().length; for (int i = 0; i < length + 4; i++) { System.out.print(decochar); } System.out.println(""); System.out.println(decochar + " " + s + " " + decochar); for (int i = 0; i < length + 4; i++) { System.out.print(decochar); } System.out.println(""); } public Product createClone() { Product p = null; try { p = (Product)clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return p; } } public class Main { public static void main(String[] args) { // 預備階段 Manager manager = new Manager(); UnderlinePen upen = new UnderlinePen('~'); MessageBox mbox = new MessageBox('*'); MessageBox sbox = new MessageBox('/'); manager.register("strong message", upen); manager.register("warning box", mbox); manager.register("slash box", sbox); // 實作產生 Product p1 = manager.create("strong message"); p1.use("Hello, world."); Product p2 = manager.create("warning box"); p2.use("Hello, world."); Product p3 = manager.create("slash box"); p3.use("Hello, world."); } } ``` ## shallow copy 淺層複製 ## deep copy 深層複製 >[name=閔致]