首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> ASP.NET 基礎 >> ASP.NET 基礎

C# 私有建構函式深度解析:單例模式、工廠模式與防實例化實戰

     編輯:ASP.NET 基礎

前言

建構函式預設為 `public`,允許外部自由建立實例。將建構函式標記為 `private` 或 `protected`,能從語言層面控制物件的建立方式,是實作單例模式、工廠模式、靜態工具類別的基石。本文深入解析私有建構函式的特性、限制與實戰應用模式。

一、私有建構函式核心特性

  1. 防止外部直接實例化:`new MyClass()` 編譯錯誤
  2. 防止繼承:衍生類別無法呼叫 `base()`,導致無法繼承
  3. 允許內部建立實例:類別自身的靜態/實例方法仍可 `new MyClass()`
  4. 常搭配靜態成員:提供 `static` 工廠方法或單例存取點

二、編譯期限制驗證

1. 無法被繼承

public class Animal
{
    private Animal() { Console.WriteLine("Animal ctor"); }
}

public class Dog : Animal  // 編譯錯誤 CS0122:'Animal.Animal()' 因保護層級而無法存取
{
}

繼承私有建構函式編譯錯誤

2. 無法被外部實例化

public class Program
{
    static void Main()
    {
        Animal a = new Animal(); // 編譯錯誤 CS0122
    }
}

public class Animal
{
    private Animal() { }
}

實例化私有建構函式編譯錯誤

三、核心應用模式

模式一:單例模式 - 經典雙重檢查鎖定

public sealed class Singleton
{
    private static volatile Singleton _instance;
    private static readonly object _lock = new object();

    private Singleton() 
    {
        Console.WriteLine("Singleton 建構函式執行");
        // 初始化昂貴資源:資料庫連線、設定檔載入等
    }

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

    public void DoWork() => Console.WriteLine("執行業務邏輯");
}

// 使用
Singleton.Instance.DoWork();

模式二:靜態工廠方法 - 具名建構語意

public class DatabaseConnection
{
    public string ConnectionString { get; }
    public int Timeout { get; }

    private DatabaseConnection(string connStr, int timeout)
    {
        ConnectionString = connStr;
        Timeout = timeout;
    }

    /// <summary>建立預設連線</summary>
    public static DatabaseConnection CreateDefault() 
        => new DatabaseConnection("Server=.;Database=Test;Integrated Security=true;", 30);

    /// <summary>建立唯讀複本連線</summary>
    public static DatabaseConnection CreateReadOnlyReplica() 
        => new DatabaseConnection("Server=Replica;Database=Test;Integrated Security=true;", 10);

    /// <summary>從組態區段建立</summary>
    public static DatabaseConnection FromConfiguration(string sectionName)
    {
        var config = ConfigurationManager.ConnectionStrings[sectionName];
        return new DatabaseConnection(config.ConnectionString, 30);
    }
}

// 使用:語意清晰,無法誤用
var conn1 = DatabaseConnection.CreateDefault();
var conn2 = DatabaseConnection.CreateReadOnlyReplica();
var conn3 = DatabaseConnection.FromConfiguration("ProductionDB");

模式三:防實例化的靜態工具類別

public static class MathUtils
{
    // C# 靜態類別隱含私有建構函式,無法實例化、無法繼承
    // 但若為非靜態類別需手動加私有建構函式:
    
    // private MathUtils() { } // 明確防止實例化
    
    public static double CalculateDistance(Point a, Point b) 
        => Math.Sqrt(Math.Pow(a.X - b.X, 2) + Math.Pow(a.Y - b.Y, 2));
    
    public static bool IsPrime(int n)
    {
        if (n < 2) return false;
        for (int i = 2; i * i <= n; i++)
            if (n % i == 0) return false;
        return true;
    }
}

模式四:受控實例建立 - 物件池/快取

public class ExpensiveResource
{
    private static readonly ConcurrentDictionary _cache 
        = new ConcurrentDictionary();
    
    public string ResourceKey { get; }
    public byte[] Data { get; }

    private ExpensiveResource(string key)
    {
        ResourceKey = key;
        Data = LoadFromDiskOrNetwork(key); // 昂貴操作
    }

    public static ExpensiveResource GetOrCreate(string key)
    {
        return _cache.GetOrAdd(key, k => new ExpensiveResource(k));
    }

    public static void Invalidate(string key) => _cache.TryRemove(key, out _);
    public static void Clear() => _cache.Clear();
}

四、protected 建構函式:允許繼承但控制實例化

public abstract class EntityBase
{
    public int Id { get; protected set; }
    
    protected EntityBase() { } // 衍生類別可呼叫,外部不可 new
    
    protected EntityBase(int id) => Id = id;
}

public class User : EntityBase
{
    public string Name { get; set; }
    
    public User() : base() { } // 必須明確呼叫 base()
    public User(int id, string name) : base(id) { Name = name; }
}

// 外部無法 new EntityBase(),但可 new User()
var user = new User(1, "Tom");

五、現代 C# 語法糖補充

C# 11+ `required` 關鍵字(替代建構函式強制參數)

public class Config
{
    public required string ApiKey { get; init; }
    public required string Endpoint { get; init; }
    public int Timeout { get; init; } = 30;
}

// 呼叫端必須提供 required 屬性
var cfg = new Config { ApiKey = "key", Endpoint = "https://api" };

Record 類型(C# 9+)不可變物件的現代寫法

public record UserDto(int Id, string Name, string Email); 

// 自動產生:建構函式、不可變屬性、with-expression、ToString、Equality
var user = new UserDto(1, "Tom", "tom@example.com");
var updated = user with { Name = "Tommy" };

六、設計決策對照表

需求建構函式類別修飾詞適用模式
全域唯一實例privatesealed classSingleton
語意化建構、驗證邏輯privateclassStatic Factory
純靜態方法、無狀態private (隱含)static classUtility Class
基底類別、需繼承protectedabstract classTemplate Method
不可變資料傳輸public (自動)recordDTO / Value Object

總結

私有建構函式是「封裝物件建立邏輯」的核心工具。它不只是語法限制,更是設計意圖的宣示:此類別的實例建立受控、有條件、有語意。善用私有建構函式搭配靜態工廠方法、單例、物件池等模式,能寫出更安全、更具表達力、更易測試的 C# 程式碼。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved