6. Singleton


Posted by WayneCheng on 2021-01-13

關於 Singleton 本篇將討論以下幾個問題

1. 關於 Singleton

2. UML

3. 將 UML 轉為程式碼

4. 情境


測試環境:

OS:Windows 10
IDE:Visual Studio 2019


1. 關於 Singleton

Ensure a class only has one instance, and provide a global point of access to it.

by Gang of Four

  • 確保 Singleton class 只有一個實體,並提供全局對這個實體的訪問點

Singleton(單例)屬於創建型(Creational Patterns),當遇到不同呼叫端需要取得相同實體時可以使用 singleton,不過 singleton 由於許多缺點,所以並不建議用於解決複雜情形的簡化,而是在取得相同實體時才採用。

優點:

  • 確保每次取得都是同一個實體,只有實體不存在時才需要初始化

缺點:

  • 需考慮到 thread safe 問題
  • 對於抽象、繼承、多型支援度較差
  • 單元測試較麻煩

2. UML

Class:

  • Singleton:作為單例的實體

3. 將 UML 轉為程式碼

此範例的寫法不是 thread safe,關於 Singleton 的 thread safe 寫法可參考 C# in Depth

建立Singleton實體,_instance 不存在才會 new 出新的實體

/// <summary>
/// Singleton 實體
/// </summary>
public class Singleton
{
    private static Singleton _instance;

    // 建構子通常為 protected or private,避免由外部建立實體
    protected Singleton()
    {
    }

    public static Singleton Instance()
    {
        // 使用延遲載入,此方式並非 thread safe
        return _instance ??= new Singleton();
    }
}
  1. 分別呼叫Singleton.Instance()取得實體
  2. 比較兩次取得的實體是否相同
static void Main(string[] args)
{
    Default.Singleton singletonA = Default.Singleton.Instance();
    Default.Singleton singletonB = Default.Singleton.Instance();

    if (singletonA == singletonB)
    {
        Console.WriteLine("\nSame instance");
    }

    Console.ReadLine();
}

執行結果

Same instance

4. 情境

我們接到了一個線上商城取得倉庫庫存量資訊的需求

  • 倉庫庫存資訊不提供外部修改
  • 倉庫庫存資訊資料量很大,很佔記憶體空間

建立InStockModel實體,_instance不存在才會 new 出新的實體

/// <summary>
/// Singleton 實體
/// </summary>
public class InStockModel
{
    private static InStockModel _instance;

    protected InStockModel()
    {
        Console.WriteLine($"Get in stock data by API.");
    }

    public static InStockModel Instance()
    {
        // 使用延遲載入,此方式並非 thread safe
        return _instance ??= new InStockModel();
    }
}
  1. 分別呼叫InStockModel.Instance()取得實體
  2. 確認是否只有在第一次呼叫時進入建構子
  3. 比較兩次取得的實體是否相同
static void Main(string[] args)
{
    Situation.InStockModel inStockModelA = Situation.InStockModel.Instance();
    Situation.InStockModel inStockModelB = Situation.InStockModel.Instance();

    if (inStockModelA == inStockModelB)
    {
        Console.WriteLine("\nSame instance");
    }

    Console.ReadLine();
}

執行結果

Get in stock data by API.

Same instance

完整程式碼

GitHub:Creational_05_Singleton


總結

Singleton 使用上簡單易上手,常被直接做為掌控度較高的全域變數使用,但會使使用端與 Singleton 類別之間耦合度提高,且儘管程式內部沒有以多執行緒方式運行,不過單元測試執行時是以多執行緒進行,若沒處理 thread safe 則依然可能會遇到單元測試時過時不過的問題。


參考資料

  1. Design Patterns
  2. 大話設計模式
  3. dofactory
  4. Refactoring.Guru
  5. C# in Depth

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


#designpattern #CSharp







Related Posts

Day 26-List/Dictionary Comprehension & NATO Alphabet project

Day 26-List/Dictionary Comprehension & NATO Alphabet project

什麼是 樣板引擎(Template Engine) ?

什麼是 樣板引擎(Template Engine) ?

BoF 理論簡介(1)

BoF 理論簡介(1)


Comments