設計模式是軟體開發中經驗的結晶,為常見問題提供經驗證可行的解決方案。本系列文章將介紹幾個流行的設計模式,並以 C# 為語言展示其精髓,幫助你建立更具擴展性、可重用的物件導向架構。
確保某個類別在整個應用程式中只有唯一實例,並提供全域存取點。例如 MFC 中的 CWinApp 應用程式類別即為單例。
public sealed class Singleton
{
private static readonly Lazy _instance =
new Lazy(() => new Singleton());
private Singleton() { } // 私有建構子,防止外部實例化
public static Singleton Instance => _instance.Value;
}
關鍵點:
private,防止直接 new。Instance 屬性回傳唯一實例。Lazy<T> 確保執行緒安全與延遲初始化(.NET 4.0+)。單例模式可擴展為「多例」,例如工作者執行緒池:
public class WorkerPool
{
private static readonly Dictionary _instances = new();
private static readonly object _lock = new object();
private readonly int _maxWorkers;
private WorkerPool(int maxWorkers) => _maxWorkers = maxWorkers;
public static WorkerPool GetInstance(int maxWorkers = 1)
{
lock (_lock)
{
if (!_instances.TryGetValue(maxWorkers, out var instance))
_instances[maxWorkers] = instance = new WorkerPool(maxWorkers);
return instance;
}
}
}
C# 由 GC 自動管理記憶體,單例生命週期無需手動釋放;C++ 需考慮解構時機與記憶體洩漏問題。C# 實作更簡潔安全。
定義一系列演算法,將各自封裝並使其可互換。讓演算法的變化獨立於使用它的客戶端。
// 策略介面
public interface IPrimeTestStrategy
{
bool IsPrime(int n);
}
// 具體策略
public class MillerRabinStrategy : IPrimeTestStrategy
{
public bool IsPrime(int n)
{
Console.WriteLine("Using Miller-Rabin algorithm");
// 實作細節略
return true;
}
}
public class FermatStrategy : IPrimeTestStrategy
{
public bool IsPrime(int n)
{
Console.WriteLine("Using Fermat algorithm");
return true;
}
}
public class MersenneStrategy : IPrimeTestStrategy
{
public bool IsPrime(int n)
{
Console.WriteLine("Using Mersenne algorithm");
return true;
}
}
// Context
public class PrimalityTester
{
private readonly IPrimeTestStrategy _strategy;
public PrimalityTester(IPrimeTestStrategy strategy)
{
_strategy = strategy;
}
public bool Test(int n) => _strategy.IsPrime(n);
}
// 客戶端使用
public class Program
{
public static void Main()
{
Console.Write("Number to test: ");
int n = int.Parse(Console.ReadLine());
Console.Write("Performance (low/medium/high): ");
string level = Console.ReadLine().ToLower();
IPrimeTestStrategy strategy = level switch
{
"low" => new MillerRabinStrategy(),
"medium" => new FermatStrategy(),
"high" => new MersenneStrategy(),
_ => throw new ArgumentException("Invalid level")
};
var tester = new PrimalityTester(strategy);
bool result = tester.Test(n);
Console.WriteLine($"Result: {result}");
}
}
if/else 或 switch。Singleton 確保全域唯一存取點,Strategy 讓演算法族群可換拔。兩者皆體現「封裝變化」的核心思想,是建立彈性架構的基石。下一篇將介紹 Decorator 與 Composite 模式。