Computer >> 컴퓨터 >  >> 프로그래밍 >> C#

C#에서 싱글톤 클래스를 sealed로 선언해야 하는 이유


C#에서 sealed 키워드는 해당 클래스를 더 이상 상속할 수 없다는 의미입니다. 반면 생성자를 private으로 선언하면 클래스 외부에서 인스턴스를 생성할 수 없게 됩니다.

그런데 여기서 주의할 점이 있습니다. private 생성자를 가진 기본 클래스라 하더라도 상속 자체는 여전히 가능합니다. 파생 클래스에서 public 생성자를 새로 정의하면, 그 과정에서 기본 클래스의 생성자가 호출되어 결국 기본 클래스의 인스턴스까지 만들어지게 됩니다.

핵심은 두 가지입니다. 첫째, 생성자는 상속되지 않습니다. 즉, 기본 클래스의 생성자가 모두 private이라 해서 파생 클래스가 자동으로 private 생성자를 갖는 것은 아닙니다. 둘째, 파생 클래스는 객체 생성 시 항상 기본 클래스의 생성자를 먼저 호출합니다.

따라서 클래스를 sealed로 선언하면 다른 개발자가 상속을 통해 신중하게 설계된 싱글톤 구조를 쉽게 우회하는 것을 차단할 수 있습니다. 이것이 싱글톤 클래스를 항상 봉인(sealed) 처리해야 하는 핵심 이유입니다.

예제 코드

static class Program {
    static void Main(string[] args){
        Singleton fromStudent = Singleton.GetInstance;
        fromStudent.PrintDetails("From Student");

        Singleton fromEmployee = Singleton.GetInstance;
        fromEmployee.PrintDetails("From Employee");

        Console.WriteLine("-------------------------------------");

        Singleton.DerivedSingleton derivedObj = new Singleton.DerivedSingleton();
        derivedObj.PrintDetails("From Derived");
        Console.ReadLine();
    }
}
public class Singleton {
    private static int counter = 0;
    private static object obj = new object();

    private Singleton() {
        counter++;
        Console.WriteLine("Counter Value " + counter.ToString());
    }
    private static Singleton instance = null;

    public static Singleton GetInstance{
        get {
            if (instance == null)
                instance = new Singleton();
            return instance;
        }
    }

    public void PrintDetails(string message){
        Console.WriteLine(message);
    }

    public class DerivedSingleton : Singleton {
    }
}

위 예제의 Singleton 클래스는 sealed로 선언되지 않았습니다. 그 결과 중첩 클래스인 DerivedSingleton이 Singleton을 상속할 수 있으며, 중첩 클래스는 외부 클래스의 private 멤버에 접근할 수 있으므로 private 생성자 호출까지 가능해집니다.

프로그램을 실행하면 GetInstance를 통해 최초 인스턴스가 생성될 때 "Counter Value 1"이 출력되고, fromEmployee는 동일한 인스턴스를 재사용하므로 카운터가 늘어나지 않습니다. 그러나 DerivedSingleton 객체를 생성하는 순간 기본 클래스의 생성자가 다시 호출되어 "Counter Value 2"가 출력됩니다. 즉, 단 하나의 인스턴스만 존재해야 한다는 싱글톤 패턴의 핵심 규칙이 상속 하나로 무너지는 것입니다.

클래스 선언부를 public sealed class Singleton으로 변경하면 이러한 상속 시도가 컴파일 오류로 차단되며, 싱글톤 패턴의 무결성을 확실하게 보장할 수 있습니다.