2013年10月21日 星期一

Prototype

Prototype 這個設計模式就我的理解來說,要解決的問題簡單的說有三個。
1. 減少 "類別" 的數量
2. 減少一個類別中的 "建構式" 的數量以控制類別的程式碼行數
3. 精準的產生不同群組的物件

以下簡單的用 C# 列出一個例子,假設我們要在遊戲畫面上產生許多不規則顏色及型狀的色塊,在未導入 Prototype Pattern 時,一般的方式我們可能會這個樣子寫

class Shape
{
    public Shape()
        : this(Colors.Red, 10, 10, 10, 10)
    {
    }

    public Shape(Color color, int width, int height, int left, int top)
        : this(color, width, height, left, top, false)
    {
    }

    public Shape(Color color, int width, int height, int left, int top, Boolean halo)
        : this(color, width, height, left, top, halo, 3)
    {
    }

    public Shape(Color color, int width, int height, int left, int top, Boolean halo, int edge)
    {
        // 實際依參數產生型狀物件的程式碼
    }
}

如果是一個可以用預設參數的語言,可能可以把上面數個建構式合併成一個,但類別可變的屬性一多,免不了建構式就會愈來愈複雜,在產生多個物件的這種程式碼片段看起來也會很複雜,例如我們產生 3 個 A 樣式的物件、2 個 B 樣式的物件在畫面上,需要這樣子寫。

// A 紅色光暈三角型樣式
Shape sr1 = new Shape(Colors.Red, 10, 10, 10, 10, true, 3);
Shape sr2 = new Shape(Colors.Red, 10, 10, 10, 10, true, 3);
Shape sr3 = new Shape(Colors.Red, 10, 10, 10, 10, true, 3);

// B 黃色五角型樣式
Shape sy1 = new Shape(Colors.Yello, 10, 10, 10, 10, true, 5);
Shape sy2 = new Shape(Colors.Yello, 10, 10, 10, 10, true, 5);

以上寫法是利用建構式來初始化物件,相對於把物件 new 出來後再一個一個屬性去調整還算是比較簡潔的寫法了,但看起來依然有點亂且難以管理,如果今天想把上面 3 個紅色的物件改成藍色的,就得改掉上面三行的參數,在沒睡飽的情況下是很容易改錯的。

而 Propotype 可以用來解決這種問題,我們把所有的建構式都移除,並且為 Shape 加入一個 Prototype Pattern 的必要特性,也就是名為 Clone 的 Method,寫法如下

Shape shapePrototype = new Shape();
shapePrototype.Foreground = Colors.Red;
shapePrototype.Width = 10;
shapePrototype.Height = 10;
shapePrototype.Top = 10;
shapePrototype.Left = 10;
shapePrototype.Halo = true;
shapePrototype.Edge = 3;

Shape redShape1 = shapePrototype.Clone();
Shape redShape2 = shapePrototype.Clone();
Shape redShape3 = shapePrototype.Clone();

shapePrototype.Foreground = Color.Yellow;
shapePrototype.Edge = 5;

Shape yellowShape1 = shapePrototype.Clone();
Shape yellowShape2 = shapePrototype.Clone();

以上程式碼可以再把所有參數包裝成另一個類別,讓 Shape 再多一個吃 ShapeParam 參數的建構式,程式碼會更清晰,而且在這種 Prototype 的寫法之下,我們想要把同一個群組的物件一起改變某些值時,需要調整的地方就只有一個,程式碼很清楚的表達了哪些是一群一樣的物件,比上一個範例來得不眼花撩亂。

比較需要注意的是,類別的 Clone Method 其實並沒有想像中的好寫,如果類別中包著類別,就得在成員中也加入具有 Clone 功能的 Method 以確保不是共用 Reference,因為在 C# 中 class 預設是 by reference 的,只有 struct 是 by value 的。

沒有留言:

張貼留言