Singleton Pattern รับประกันว่ามี Instance ของคลาสเพียง Instance เดียวตลอด Lifetime ของ Application
การประกาศ sealed มีความสำคัญ 2 ข้อ:
1. ป้องกัน Inheritance (สาเหตุหลัก)
public class Singleton
{
private static Singleton _instance;
private static readonly object _lock = new object();
private Singleton() { } // Private Constructor
public static Singleton Instance
{
get
{
if (_instance == null)
{
lock (_lock)
{
if (_instance == null)
_instance = new Singleton();
}
}
return _instance;
}
}
}
// หากไม่ sealed - สามารถสร้าง Subclass ได้!
public class DerivedSingleton : Singleton // ❌ ถ้าไม่ sealed จะทำได้
{
// สร้าง Instance ใหม่ได้อีก!
public static DerivedSingleton NewInstance => new DerivedSingleton();
}
หากไม่ sealed ผู้อื่นสามารถ:
- สร้าง Subclass ที่มี Public Constructor
- สร้าง Instance ใหม่หลาย Instance (破坏 Singleton Guarantee)
- Override เมธอด/Property เปลี่ยนพฤติกรรม
2. เพิ่มโอกาสให้ Compiler/JIT Optimize
sealedบอก Compiler ว่าคลาสนี้ไม่มี Subclass- ทำให้ Devirtualization เรียก Method ได้เร็วขึ้น (Non-virtual Call)
- Inlining ได้ง่ายขึ้น
Singleton แบบ Modern (Thread-safe, Lazy, Sealed)
public sealed class Singleton // ✅ Sealed
{
// Lazy<T> Thread-safe โดยค่าเริ่มต้น (LazyThreadSafetyMode.ExecutionAndPublication)
private static readonly Lazy<Singleton> _instance =
new Lazy<Singleton>(() => new Singleton());
private Singleton() { } // Private Constructor
public static Singleton Instance => _instance.Value;
public void DoWork() => Console.WriteLine("Singleton working...");
}
การทดสอบ
static void Main()
{
var s1 = Singleton.Instance;
var s2 = Singleton.Instance;
Console.WriteLine($"Same instance? {ReferenceEquals(s1, s2)}"); // True
// DerivedSingleton derived = new DerivedSingleton(); // ❌ Compile Error: Cannot derive from sealed type
}
สรุป
sealed = ป้องกัน Inheritance = รับประกัน Singleton Property- Private Constructor = ป้องกัน Instantiation จากภายนอก
- ใช้
Lazy<T>สำหรับ Thread-safe Lazy Initialization (แทน Double-Check Locking) - ใน DI Container ใช้
services.AddSingleton<T>()แทนการเขียน Singleton เอง