簡介

模式名稱:

Singleton Pattern

問題:

在某些情況下,我們需要確保一個類只能創建一個實例,並且該實例在整個應用程序中都是全局可用的。例如,當我們需要一個全局的資料庫連接、設定管理或Log系統時,這些對象只需要一個實例即可,以避免重複創建對象的開銷和維護困難。

解決方案:

Singleton Pattern 通過將一個類的構造函數設置為私有,並提供一個靜態方法來獲取該類的唯一實例,確保了該類只有一個實例存在。在第一次調用該靜態方法時,會創建一個唯一的實例,並在以後的調用中返回相同的實例。

結果:

Singleton Pattern 可以確保類只有一個實例存在,並且該實例在整個應用程序中都是全局可用的,減少了對象的創建和維護成本。但是,Singleton Pattern 也可能引起一些問題,例如單例類可能會導致代碼的耦合度增加,並使代碼難以測試。

C#簡單實作

使用一個 private的建構式和一個 static的readonly實例,以確保只有一個Singleton實例存在。 並提供了一個 static的Instance 屬性,以便其他程式碼可以訪問 Singleton 實例。 可以使用 sealed 關鍵字來防止該類被繼承。

在 C# 中,實現 Singleton Pattern 的方式有多種,下面我們將介紹三種初始化的方式: Eager Initialization Lazy Initialization Thread-Safe Initialization

Eager Initialization

是一種在應用程式啟動時立即建立 Singleton 實例的方式。這種方式簡單易行,且 Singleton 實例會在程式一開始就建立好,並且在整個應用程式運行期間都是存在的。

以下是使用 Eager Initialization 實現 Singleton Pattern 的 C# 程式碼範例:

public sealed class Singleton
{
    private static readonly Singleton instance = new Singleton();

    private Singleton() { }

    public static Singleton Instance
    {
        get
        {
            return instance;
        }
    }
}

在這個程式碼中,Singleton 類只有一個私有的實例 instance,並通過靜態的 Instance 屬性進行訪問。Singleton 的建構函數是私有的,因此外部無法創建 Singleton 實例,只能通過 Singleton.Instance 屬性獲取唯一的實例。

Lazy Initialization

是一種在第一次調用 Singleton 實例時才建立實例的方式。這種方式可以節省系統資源,但是可能會造成執行緒安全問題,需要特別注意。

以下是使用 Lazy Initialization 實現 Singleton Pattern 的 C# 程式碼範例:

public sealed class Singleton
{
    private static readonly Lazy<Singleton> lazyInstance = new Lazy<Singleton>(() => new Singleton());

    private Singleton() { }

    public static Singleton Instance
    {
        get
        {
            return lazyInstance.Value;
        }
    }
}

在這個程式碼中,Singleton 類只有一個私有的實例 lazyInstance,並通過靜態的 Instance 屬性進行訪問。Singleton 的建構函數是私有的,因此外部無法創建 Singleton 實例,只能通過 Singleton.Instance 屬性獲取唯一的實例。使用 Lazy 類型可以實現在第一次調用時才建立 Singleton 實例的效果。

Thread-Safe Initialization

是一種在多執行緒環境下安全地創建 Singleton 實例的方式。這種方式可以保證 Singleton 實例在多執行緒環境下的唯一性和一致性,但是可能會降低效能。

以下是使用 Thread-Safe Initialization 實現 Singleton Pattern 的 C# 程式碼範例:

public sealed class Singleton
{
    private static volatile Singleton instance = null;
    private static readonly object syncRoot = new object();

    private Singleton() { }

    public static Singleton Instance
    {
        get
        {
            if (instance == null)
            {
                lock (syncRoot)
                {
                    if (instance == null)
                    {
                        instance = new Singleton();
                    }
                }
            }
            return instance;
        }
    }
}

這段程式碼中,使用了 volatile 關鍵字來保證 instance 變數的可見性。在 Singleton 類中,首先檢查 instance 是否為 null,如果是,就鎖定 syncRoot 物件,然後再次檢查 instance 是否為 null。如果仍然是 null,則創建一個新的 Singleton 實例,並將其賦值給 instance 變數。最後,釋放鎖定並返回 instance 變數的值。 雙重檢查鎖定方式可以減少多線程環境中的 lock 操作,從而提高程式碼的效率。同時也能保證 Singleton 實例只被創建一次,且線程安全。但要注意,這種方式的實現較為複雜,需要確保 instance 變數的可見性,否則可能會導致 Singleton 實例被創建多次的問題。

以上是三種常見的實現 Singleton Pattern 的方式,選擇哪一種方式取決於具體的應用場景。需要注意的是,Singleton Pattern 不應該被濫用,否則會導致程式難以測試、可讀性降低等問題。