c#

C# 디자인 패턴 입문: 싱글톤, 팩토리 등 실제 예제 가이드

개발에대해 2025. 9. 29. 13:13
반응형

 

C# 디자인 패턴 입문: 싱글톤, 팩토리 등 실제 예제 가이드

1. 디자인 패턴이란?

안녕하세요! 오늘은 C# 개발자라면 반드시 알아두면 좋은 디자인 패턴에 대해 이야기해보려고 합니다. 디자인 패턴이란 반복적으로 발생하는 소프트웨어 설계 문제를 해결하기 위한 재사용 가능한 설계 템플릿이라고 이해하면 쉽습니다. 객체지향 프로그래밍(OOP)을 하다 보면 클래스 설계, 객체 생성, 책임 분리 등에서 고민이 많은데, 디자인 패턴을 활용하면 깔끔하고 유지보수 가능한 코드를 작성할 수 있어요.

2. 싱글톤(Singleton) 패턴

싱글톤 패턴은 애플리케이션에서 특정 클래스의 인스턴스를 하나만 생성하고, 어디서든 동일한 인스턴스를 사용하도록 보장하는 패턴입니다. 주로 로깅, 설정 관리, 데이터베이스 연결 객체 등에서 활용돼요.

public class Logger
{
    private static readonly Logger _instance = new Logger();

    // 외부에서 new 키워드로 생성하지 못하도록 private
    private Logger() { }

    public static Logger Instance => _instance;

    public void Log(string message)
    {
        Console.WriteLine($"[LOG] {message}");
    }
}

사용 예제:

Logger.Instance.Log("애플리케이션 시작");

싱글톤의 장점은 전역 접근성을 제공하고, 인스턴스를 하나만 유지하여 메모리와 리소스를 효율적으로 사용할 수 있다는 점입니다. 단점은 너무 남발하면 코드 의존성이 높아지고, 테스트가 어려워질 수 있어요. 따라서 주로 상태를 공유해야 하는 곳에서만 사용하는 것이 좋습니다.

3. 팩토리(Factory) 패턴

팩토리 패턴은 객체 생성 로직을 캡슐화하여 클라이언트 코드에서 객체 생성 방식을 분리하는 패턴입니다. 즉, "무엇을 생성할지"와 "어떻게 생성할지"를 분리할 수 있어요. 예를 들어, 서로 다른 유형의 알림(Notification) 객체를 생성할 때 유용합니다.

public abstract class Notification
{
    public abstract void Notify(string message);
}

public class EmailNotification : Notification
{
    public override void Notify(string message) => Console.WriteLine($"Email: {message}");
}

public class SmsNotification : Notification
{
    public override void Notify(string message) => Console.WriteLine($"SMS: {message}");
}

public static class NotificationFactory
{
    public static Notification Create(string type)
    {
        return type.ToLower() switch
        {
            "email" => new EmailNotification(),
            "sms" => new SmsNotification(),
            _ => throw new ArgumentException("Invalid type")
        };
    }
}

사용 예제:

var notification = NotificationFactory.Create("email");
notification.Notify("디자인 패턴 학습 완료!");

팩토리 패턴을 사용하면 코드 확장성이 높아지고, 클라이언트 코드에서 객체 생성에 대한 변경 없이 새로운 타입을 쉽게 추가할 수 있습니다.

4. 전략(Strategy) 패턴

전략 패턴은 알고리즘을 캡슐화하여 실행 시점에 선택할 수 있도록 하는 패턴입니다. 예를 들어, 결제(Payment) 기능에서 신용카드, 페이팔, 카카오페이 등 다양한 결제 방식이 있을 때 유용합니다.

public interface IPaymentStrategy
{
    void Pay(decimal amount);
}

public class CreditCardPayment : IPaymentStrategy
{
    public void Pay(decimal amount) => Console.WriteLine($"신용카드 결제: {amount}원");
}

public class PaypalPayment : IPaymentStrategy
{
    public void Pay(decimal amount) => Console.WriteLine($"PayPal 결제: {amount}원");
}

public class PaymentContext
{
    private readonly IPaymentStrategy _strategy;

    public PaymentContext(IPaymentStrategy strategy)
    {
        _strategy = strategy;
    }

    public void Pay(decimal amount) => _strategy.Pay(amount);
}

사용 예제:

var payment = new PaymentContext(new CreditCardPayment());
payment.Pay(50000);

전략 패턴을 활용하면 결제 방식 추가 시 기존 코드를 수정할 필요가 없고, 책임 분리가 명확해 유지보수가 용이합니다.

5. 싱글톤 vs 팩토리 vs 전략

디자인 패턴은 서로 목적이 다르므로 상황에 맞게 선택해야 합니다.

  • 싱글톤: 인스턴스를 하나만 유지하고 전역 접근 필요 시.
  • 팩토리: 객체 생성 로직을 분리하고 확장성을 높이고 싶을 때.
  • 전략: 알고리즘을 런타임에 선택하고 책임을 분리하고 싶을 때.

실제 프로젝트에서는 세 패턴을 함께 사용하기도 합니다. 예를 들어, 싱글톤 로거를 사용하면서, 팩토리로 객체를 생성하고, 전략 패턴으로 알고리즘을 선택하는 방식이죠. 이렇게 하면 구조가 깔끔하고, 확장과 유지보수가 용이한 소프트웨어를 만들 수 있습니다.

6. 실무 적용 팁

  • 패턴은 무작정 적용하지 말고, 문제를 먼저 정의하고 적합한 패턴을 선택하세요.
  • 단일 책임 원칙(SRP)을 지키면서 패턴을 적용하면 코드 복잡도를 낮출 수 있습니다.
  • 테스트 가능성을 고려하여 패턴을 적용하면 유지보수와 확장성이 향상됩니다.
  • 팩토리나 전략을 인터페이스 기반으로 설계하면 의존성 주입(DI)과 함께 활용하기 좋습니다.
  • 디자인 패턴을 이해하면 팀 협업 시 코드 설계 의도를 명확히 전달할 수 있어요.

7. 마무리

오늘은 C# 개발자에게 중요한 디자인 패턴 입문으로, 싱글톤, 팩토리, 전략 패턴을 깊이 있게 살펴보았습니다. 예제 코드를 직접 실행해보며 객체 생성, 책임 분리, 확장성 등 각 패턴의 장점을 체감해보시길 추천드려요. 디자인 패턴은 단순한 코드 스타일이 아니라, 유지보수와 확장성, 성능을 고려한 설계 방법이므로, 꾸준히 실습하면서 익히는 것이 중요합니다. 😊

반응형