---
# System prepended metadata

title: 5. Prototype
tags: [DesignPatterns]

---

# 5. Prototype

###### tags: `DesignPatterns`

## 關於 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](https://en.wikipedia.org/wiki/Design_Patterns)

- 依據原型(的 abstract class/interface)創建出原型實體，並通過複製此原型來創建新的物件

Prototype(原型)屬於創建型(Creational Patterns)，當遇到**內部差異小但創建成本較高**(e.g. 呼叫外部資料耗時)的實體時，透過 Prototype 以複製方式來創建新的實體，跳過初始化的過程來減少資源的浪費。

優點：
- 減少反覆實體初始化的過程

缺點：
- 被複製的實體若繼承關係較複雜，則可能會大幅增加整體複雜度

---
## 2. Shallow copy(淺複製) & Deep copy(深複製)
Shallow copy(淺複製)
- 只複製記憶體位置
- 被複製物件修改可能會將複製物件一同修改

Deep copy(深複製)
- 建立新記憶體位置，並放置一份相同的資料
- 被複製物件與複製物件各自獨立

---
## 3. UML
![](https://i.imgur.com/ohAInaK.jpg)
Class 間關聯：
- Client 關聯 Prototype
- ConcretePrototype 繼承 Prototype

Class：
- Client：呼叫端
- Prototype：原型的抽象類別或介面
- ConcretePrototype：原型的實作，在類別中加上複製邏輯

---
## 4. 將 UML 轉為程式碼
這邊所使用的複製方法 MemberwiseClone() 請參考 [MSDN](https://docs.microsoft.com/zh-tw/dotnet/api/system.object.memberwiseclone?view=net-5.0)

原型的介面
```C#
/// <summary>
/// 原型的介面
/// </summary>
public interface IPrototype
{
    string Id { get; }

    public IPrototype Clone();
}
```
原型實作
```C#
/// <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();
    }
}
```

1. 建立類別
2. 呼叫`Clone()`取得複製類別

```C#
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();
}
```
執行結果
```Console
Cloned: Test
```

---
## 5. 情境
我們接到了一個數間門市每天開店時要取得倉庫庫存量資訊的需求
- 不同分店會有各自資訊要記錄
- 倉庫庫存資訊資料量很大，API 傳輸很慢

分店資訊介面
```C#
/// <summary>
/// 分店資訊介面
/// </summary>
public interface IStore
{
    string StoreId { get; set; }

    string InStockData { get; set; }

    public IStore Clone(string storeId);
}
```
分店資訊實作
```C#
/// <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;
    }
}
```

1. 先建立 Taipei 店物件
2. 取得庫存資訊
3. 呼叫`Clone()`
4. 由 Clone 取得的 Tainan 店不需要再次呼叫取得庫存資訊

```C#
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();
}
```
執行結果
```Console
取得 庫存量
Store StoreId: Taipei
Store InStockData: 庫存量
Clone StoreId: Tainan
Clone InStockData: 庫存量
```

---
## 完整程式碼
GitHub：[Creational_04_Prototype](https://github.com/darionnnnnn/blog/tree/master/Blog/Creational_04_Prototype)
   
---
## 總結
### 範例中只對於 Prototype 的重點實作，實際上 Clone() 內要使用 Shallow copy(淺複製)、Deep copy(深複製)或是自訂的複製方法都可以，且除了範例中複製大量資訊避免還要花時間重新載入之外，對於只有建構時需要消耗大量資源的運算、I/O等，都可以藉由 Prototype 來減少資源的消耗。

---
## 參考資料
1. [Design Patterns](https://en.wikipedia.org/wiki/Design_Patterns)
2. [大話設計模式](https://www.tenlong.com.tw/products/9789866761799)
2. [dofactory](https://www.dofactory.com/)
3. [Refactoring.Guru](https://refactoring.guru/)

---

## 新手上路，若有錯誤還請告知，謝謝
