---
# System prepended metadata

title: 原型模式 Prototype
tags: [Creational Patterns]

---

---
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=閔致]