原型模式 Prototype Pattern

1046 字
5 分鐘
原型模式 Prototype Pattern

目的#

制訂可用原型個體生成的物件類型,爾後只須複製此原型即可生成新物件

適用#

當系統必須與成品物件的生成、組裝、表達方式保持獨立時以及下面三種情況之一

  • 在Runtime才指明欲實體化哪一種類別時(如:動態載入);或避免造出與成品物件平行的一整族factory類別階層時;或當類別的物件個體只可能處於少數幾種可能的狀態時,替各種可能的狀態安置原型個體讓人複製,會比手動實體化類別來得方便。

結構及成員#

Collaborations: Client叫Prototype自我複製一份。

  • Prototype: like the Graphic宣告自我複製的介面。Client:叫原型個體自我複製一份,以生出新的物件。ConcretePrototype: like the Staff, WholeNote, HalfNote具體實作出自我複製的方法。
//必須實作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;
}
}

影響結果#

好處#

  • 將ConcreteProduct類別隱藏起來,減少Client所能知道的類別種類,也能不修改Client即可與其他應用領域的類別協同運作。在執行期增刪成品物件類型:只要向Client註冊Prototype,就能引進新的成品物件類型,且Client可以在執行期安裝或卸除Prototype。改變內容以訂出新的物件:可透過物件複合方式制定新的行為(如:指定物件的個體變數內容)。改變結構以訂出新的物件:將小電路當原型個體,拿到電路元件上擺著。只要複合電路物件的clone()方法採取deep copy,就能將各種不同的電路結構視為原型個體來用。減少子類別數量:不像 Factory Method Pattern 會產生與成品物件類別階層平行對應的Creator類別階層,只要複製原型個體即可。

壞處#

  • 每一個Prototype子類別都必須實作clone()方法,若是想把clone()加到早已存在的類別裡,或是類別裡有不支援複製動作的物件,或是有循環指涉(circular reference)的情形,就更不容易製作clone()。

實作#

使用原型個體管理者#

  • 若系統內原型個體的數量不固定(會動態產生及撤銷)。用登錄表註冊存取原型個體後再複製。

製作clone()方法#

  • 複製物件時是否會遞迴地將內含的個體變數也一併拷貝?若物件有save()和load()方法,就能先將物件save到記憶體緩衝區,再從緩衝區load到另一個物件身上。

初始化複製品#

  • clone()方法通常不允許傳遞初始化參數。可另外寫Initialize()方法進行參數的設定。若clone()方法是深層拷貝,則要先刪除內部的複製品。

Example: Shape#

Class: Shape
package shape;
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;
}
}
Class: Rectangle
package shape;
public class Rectangle extends Shape {
public Rectangle(){
type = "Rectangle";
}
@Override
public void draw() {
System.out.println("Inside Rectangle::draw() method.");
}
}
Interface: Square
package shape;
public class Square extends Shape {
public Square(){
type = "Square";
}
@Override
public void draw() {
System.out.println("Inside Square::draw() method.");
}
}
Class: Circle
package shape;
public class Circle extends Shape {
public Circle(){
type = "Circle";
}
@Override
public void draw() {
System.out.println("Inside Circle::draw() method.");
}
}
Class: ShapeCache
package shape;
import java.util.Hashtable;
public class ShapeCache {
private static Hashtable shapeMap = new Hashtable();
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);
}
}
Class: PrototypePatternDemo
package shape;
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());
}
}
Result:
Shape : Circle
Shape : Square
Shape : Rectangle

文章分享

如果這篇文章對你有幫助,歡迎分享給更多人!

原型模式 Prototype Pattern
https://linziyou.info/posts/2020-12-22-原型模式-prototype-pattern/
作者
Lin Ziyou
發布於
2020-12-22
許可協議
CC BY-NC-SA 4.0
最後更新於 2020-12-22,距今已過 1896 天

部分內容可能已過時

Profile Image of the Author
Lin Ziyou
Hi! I'm Jerry~
分類
標籤
站點統計
文章
45
分類
8
標籤
10
總字數
43,470
運作天數
0
最後活動
0 天前

目錄