# 6. Singleton ###### tags: `DesignPatterns` ## 關於 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](https://en.wikipedia.org/wiki/Design_Patterns) - 確保 Singleton class 只有一個實體,並提供全局對這個實體的訪問點 Singleton(單例)屬於創建型(Creational Patterns),當遇到不同呼叫端需要取得**相同實體**時可以使用 singleton,不過 singleton 由於許多缺點,所以並不建議用於解決複雜情形的簡化,而是在取得相同實體時才採用。 優點: - 確保每次取得都是同一個實體,只有實體不存在時才需要初始化 缺點: - 需考慮到 thread safe 問題 - 對於抽象、繼承、多型支援度較差 - 單元測試較麻煩 --- ## 2. UML  Class: - Singleton:作為單例的實體 --- ## 3. 將 UML 轉為程式碼 此範例的寫法不是 thread safe,關於 Singleton 的 thread safe 寫法可參考 [C# in Depth](https://csharpindepth.com/Articles/Singleton) 建立`Singleton`實體,`_instance` 不存在才會 new 出新的實體 ```C# /// <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. 比較兩次取得的實體是否相同 ```C# 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(); } ``` 執行結果 ```Console Same instance ``` --- ## 4. 情境 我們接到了一個線上商城取得倉庫庫存量資訊的需求 - 倉庫庫存資訊不提供外部修改 - 倉庫庫存資訊資料量很大,很佔記憶體空間 建立`InStockModel`實體,`_instance`不存在才會 new 出新的實體 ```C# /// <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. 比較兩次取得的實體是否相同 ```C# 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(); } ``` 執行結果 ```Console Get in stock data by API. Same instance ``` --- ## 完整程式碼 GitHub:[Creational_05_Singleton](https://github.com/darionnnnnn/blog/tree/master/Blog/Creational_05_Singleton) --- ## 總結 ### Singleton 使用上簡單易上手,常被直接做為掌控度較高的全域變數使用,但會使使用端與 Singleton 類別之間耦合度提高,且儘管程式內部沒有以多執行緒方式運行,不過單元測試執行時是以多執行緒進行,若沒處理 thread safe 則依然可能會遇到單元測試時過時不過的問題。 --- ## 參考資料 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/) 4. [C# in Depth](https://csharpindepth.com/Articles/Singleton) --- ## 新手上路,若有錯誤還請告知,謝謝
×
Sign in
Email
Password
Forgot password
or
By clicking below, you agree to our
terms of service
.
Sign in via Facebook
Sign in via Twitter
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
New to HackMD?
Sign up