關於 Prototype 本篇將討論以下幾個問題
1. 關於 Prototype
2. Shallow copy(淺複製) & Deep copy(深複製)
3. UML
4. 將 UML 轉為程式碼
5. 情境
測試環境:
OS:Windows 10
IDE:Visual Studio 2019
1. 關於 Prototype
Specify the kinds of objects to create using a prototypical instance, and create new objects by copying this prototype.
by Gang of Four
- 依據原型(的 abstract class/interface)創建出原型實體,並通過複製此原型來創建新的物件
Prototype(原型)屬於創建型(Creational Patterns),當遇到內部差異小但創建成本較高(e.g. 呼叫外部資料耗時)的實體時,透過 Prototype 以複製方式來創建新的實體,跳過初始化的過程來減少資源的浪費。
優點:
- 減少反覆實體初始化的過程
缺點:
- 被複製的實體若繼承關係較複雜,則可能會大幅增加整體複雜度
2. Shallow copy(淺複製) & Deep copy(深複製)
Shallow copy(淺複製)
- 只複製記憶體位置
- 被複製物件修改可能會將複製物件一同修改
Deep copy(深複製)
- 建立新記憶體位置,並放置一份相同的資料
- 被複製物件與複製物件各自獨立
3. UML
Class 間關聯:
- Client 關聯 Prototype
- ConcretePrototype 繼承 Prototype
Class:
- Client:呼叫端
- Prototype:原型的抽象類別或介面
- ConcretePrototype:原型的實作,在類別中加上複製邏輯
4. 將 UML 轉為程式碼
這邊所使用的複製方法 MemberwiseClone() 請參考 MSDN
原型的介面
/// <summary>
/// 原型的介面
/// </summary>
public interface IPrototype
{
string Id { get; }
public IPrototype Clone();
}
原型實作
/// <summary>
/// 原型實作
/// </summary>
public class ConcretePrototype : IPrototype
{
public string Id { get; }
public ConcretePrototype(string id)
{
Id = id;
}
// Returns a shallow copy
public IPrototype Clone()
{
return (IPrototype)this.MemberwiseClone();
}
}
- 建立類別
- 呼叫
Clone()
取得複製類別
static void Main(string[] args)
{
Default.ConcretePrototype prototype = new Default.ConcretePrototype("Test");
Default.ConcretePrototype clone = (Default.ConcretePrototype)prototype.Clone();
Console.WriteLine($"Cloned: {clone.Id}");
Console.ReadLine();
}
執行結果
Cloned: Test
5. 情境
我們接到了一個數間門市每天開店時要取得倉庫庫存量資訊的需求
- 不同分店會有各自資訊要記錄
- 倉庫庫存資訊資料量很大,API 傳輸很慢
分店資訊介面
/// <summary>
/// 分店資訊介面
/// </summary>
public interface IStore
{
string StoreId { get; set; }
string InStockData { get; set; }
public IStore Clone(string storeId);
}
分店資訊實作
/// <summary>
/// 分店資訊實作
/// </summary>
public class Store : IStore
{
public string StoreId { get; set; }
public string InStockData { get; set; }
public Store(string storeId)
{
StoreId = storeId;
}
public void GetInStockData()
{
InStockData = "庫存量";
Console.WriteLine($"取得 {InStockData}");
}
// Returns a shallow copy
public IStore Clone(string storeId)
{
var clone = (IStore) this.MemberwiseClone();
clone.StoreId = storeId;
return clone;
}
}
- 先建立 Taipei 店物件
- 取得庫存資訊
- 呼叫
Clone()
- 由 Clone 取得的 Tainan 店不需要再次呼叫取得庫存資訊
static void Main(string[] args)
{
Situation.Store store = new Situation.Store("Taipei");
store.GetInStockData();
Situation.Store clone = (Situation.Store)store.Clone("Tainan");
Console.WriteLine($"Store StoreId: {store.StoreId}");
Console.WriteLine($"Store InStockData: {store.InStockData}");
Console.WriteLine($"Clone StoreId: {clone.StoreId}");
Console.WriteLine($"Clone InStockData: {clone.InStockData}");
Console.ReadLine();
}
執行結果
取得 庫存量
Store StoreId: Taipei
Store InStockData: 庫存量
Clone StoreId: Tainan
Clone InStockData: 庫存量
完整程式碼
GitHub:Creational_04_Prototype