1. 개요

소프트웨어 개발을 하다 보면 알고리즘이나 동작 방식을 상황에 따라 유연하게 변경해야 할 때가 많습니다. Strategy 패턴은 이러한 문제를 해결하기 위해 고안된 디자인 패턴으로, 알고리즘을 캡슐화하여 서로 교체 가능하도록 만드는 것을 목표로 합니다. 이 글에서는 Strategy 패턴의 개념, C# 구현 예제, 그리고 사용 시 주의할 점을 알아보겠습니다.


2. 개념

Strategy 패턴은 다음과 같은 상황에서 유용합니다:

  • 여러 알고리즘 중에서 런타임에 하나를 선택해야 하는 경우.
  • 특정 동작을 다른 객체와 독립적으로 교체하거나 확장하고 싶은 경우.

Strategy 패턴의 핵심은 "행동(Behavior)을 객체로 캡슐화"하여 클라이언트 코드에서 알고리즘을 직접 변경하지 않고도 동작을 바꿀 수 있도록 하는 것입니다.

구조는 다음과 같습니다:

  1. Context: 전략 객체를 사용하는 주요 클래스.
  2. Strategy: 알고리즘의 인터페이스.
  3. ConcreteStrategy: 특정 알고리즘을 구현한 클래스.

3. 예제

요구사항

사용자가 할인 정책을 선택할 수 있는 온라인 쇼핑몰을 만든다고 가정합시다. 할인 정책에는 다음이 포함됩니다:

  • 기본 할인 없음
  • 정률 할인 (10% 할인)
  • 정액 할인 (5,000원 할인)

코드 구현

// Strategy 인터페이스
public interface IDiscountStrategy
{
    decimal ApplyDiscount(decimal price);
}

// ConcreteStrategy: 기본 할인 없음
public class NoDiscountStrategy : IDiscountStrategy
{
    public decimal ApplyDiscount(decimal price)
    {
        return price;
    }
}

// ConcreteStrategy: 정률 할인
public class PercentageDiscountStrategy : IDiscountStrategy
{
    private readonly decimal _percentage;

    public PercentageDiscountStrategy(decimal percentage)
    {
        _percentage = percentage;
    }

    public decimal ApplyDiscount(decimal price)
    {
        return price - (price * _percentage);
    }
}

// ConcreteStrategy: 정액 할인
public class FixedDiscountStrategy : IDiscountStrategy
{
    private readonly decimal _discountAmount;

    public FixedDiscountStrategy(decimal discountAmount)
    {
        _discountAmount = discountAmount;
    }

    public decimal ApplyDiscount(decimal price)
    {
        return price - _discountAmount;
    }
}

// Context 클래스
public class ShoppingCart
{
    private IDiscountStrategy _discountStrategy;

    public ShoppingCart(IDiscountStrategy discountStrategy)
    {
        _discountStrategy = discountStrategy;
    }

    public void SetDiscountStrategy(IDiscountStrategy discountStrategy)
    {
        _discountStrategy = discountStrategy;
    }

    public decimal CalculateTotal(decimal price)
    {
        return _discountStrategy.ApplyDiscount(price);
    }
}

// 사용 예
class Program
{
    static void Main(string[] args)
    {
        decimal originalPrice = 50000m;

        // 기본 할인 없음
        var noDiscount = new ShoppingCart(new NoDiscountStrategy());
        Console.WriteLine($"No Discount: {noDiscount.CalculateTotal(originalPrice)}원");

        // 10% 정률 할인
        var percentageDiscount = new ShoppingCart(new PercentageDiscountStrategy(0.1m));
        Console.WriteLine($"10% Discount: {percentageDiscount.CalculateTotal(originalPrice)}원");

        // 5,000원 정액 할인
        var fixedDiscount = new ShoppingCart(new FixedDiscountStrategy(5000m));
        Console.WriteLine($"5,000원 Discount: {fixedDiscount.CalculateTotal(originalPrice)}원");
    }
}

4. 주의점: 남용을 피하라

Strategy 패턴은 분명 강력한 도구지만, 모든 경우에 적합하지는 않습니다. 다음 사항을 염두에 두세요:

  1. 간단한 경우에 복잡도 증가: 너무 간단한 문제를 해결하려고 Strategy 패턴을 사용하면 오히려 코드가 복잡해질 수 있습니다.
  2. 객체 생성 비용: 많은 전략 객체를 생성하고 교체하는 과정에서 성능에 영향을 줄 수 있습니다.

5. 결론

Strategy 패턴은 다양한 알고리즘을 유연하게 사용할 수 있도록 해주는 강력한 디자인 패턴입니다. 특히, 런타임에 동작 방식을 변경해야 하거나 코드의 가독성과 확장성을 높이고 싶을 때 유용합니다. 하지만 과도한 사용은 피해야 하며, 상황에 맞는지 신중히 검토해야 합니다.


6. 관련 링크

다이어그램

반응형

+ Recent posts