WPF 및 C#에서 효율적인 싱글톤 패턴 구현 방법

WPF(Windows Presentation Foundation) 애플리케이션 개발 시, 특정 데이터나 상태를 애플리케이션 전역에서 공유해야 할 때가 많습니다. 이때 가장 널리 사용되는 디자인 패턴이 싱글톤(Singleton) 패턴입니다. 싱글톤 패턴은 클래스의 인스턴스를 단 하나만 생성하도록 보장하여 메모리 낭비를 줄이고 데이터의 일관성을 유지하는 데 도움을 줍니다.

1. 기본적인 싱글톤과 속성 변경 알림 구현

WPF의 데이터 바인딩과 연동하기 위해서는 싱글톤 클래스에 INotifyPropertyChanged 인터페이스를 구현하는 것이 좋습니다. 이를 통해 싱글톤 인스턴스 내부의 값이 변경될 때 UI가 자동으로 업데이트됩니다.

using System.ComponentModel;
using System.Runtime.CompilerServices;

public class AppStateManager : INotifyPropertyChanged
{
    private static AppStateManager _instance;
    private string _statusMessage;

    // 외부에서 인스턴스화를 방지하기 위한 private 생성자
    private AppStateManager() { }

    // 전역 접근 지점
    public static AppStateManager Instance => _instance ??= new AppStateManager();

    public string StatusMessage
    {
        get => _statusMessage;
        set
        {
            if (_statusMessage != value)
            {
                _statusMessage = value;
                OnPropertyChanged();
            }
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

2. 정적 초기화를 이용한 단순한 싱글톤

가장 단순한 형태의 싱글톤은 정적 필드 초기화 기능을 사용하는 것입니다. .NET의 정적 생성자는 스레드 안전(Thread-safe)을 보장하므로 복잡한 로직 없이도 안전하게 인스턴스를 생성할 수 있습니다.

public sealed class LoggerService
{
    // 클래스 로드 시 인스턴스 생성 (Eager Initialization)
    private static readonly LoggerService _instance = new LoggerService();

    private LoggerService() 
    {
        ServiceName = "Standard Logger";
    }

    public static LoggerService Instance => _instance;

    public string ServiceName { get; }

    public void WriteLog(string message)
    {
        System.Diagnostics.Debug.WriteLine($"[{DateTime.Now}] {message}");
    }
}

3. 스레드 안전을 보장하는 이중 확인 잠금(Double-Checked Locking)

멀티스레드 환경에서 인스턴스가 필요한 시점에만 생성(Lazy Initialization)되도록 하려면 lock 키워드를 활용한 이중 확인 잠금 방식을 사용할 수 있습니다.

public sealed class DatabaseConnector
{
    private static DatabaseConnector _instance = null;
    private static readonly object _lockHandle = new object();

    private DatabaseConnector() 
    {
        ConnectionID = Guid.NewGuid().ToString();
    }

    public static DatabaseConnector Instance
    {
        get
        {
            // 첫 번째 체크: 락을 걸기 전 성능 최적화
            if (_instance == null)
            {
                lock (_lockHandle)
                {
                    // 두 번째 체크: 인스턴스 생성 여부 재확인
                    if (_instance == null)
                    {
                        _instance = new DatabaseConnector();
                    }
                }
            }
            return _instance;
        }
    }

    public string ConnectionID { get; private set; }

    public void Connect()
    {
        // 연결 로직 구현
    }
}

위의 예제들처럼 싱글톤 패턴을 적용하면 WPF 애플리케이션 내의 다양한 ViewModel이나 View에서 동일한 데이터 소스에 접근할 수 있습니다. AppStateManager.Instance.StatusMessage = "Ready";와 같은 방식으로 전역 상태를 손쉽게 관리할 수 있습니다.

태그: WPF C# singleton-pattern design-patterns .NET

6월 10일 01:50에 게시됨