Workspace/Design Pattern

데코레이터 패턴 (Decorator Pattern): 유연한 기능 확장의 비밀

Bombus 2025. 1. 22. 12:13

1. 개요

디자인 패턴 중 Decorator 패턴은 기존 객체에 새로운 기능을 동적으로 추가하고 싶을 때 유용한 패턴입니다. 상속 없이도 객체의 행동을 확장할 수 있어, 코드 재사용성과 유지보수성을 높이는 데 탁월합니다. 🎯


2. 개념

Decorator 패턴은 객체를 감싸는(wrapper) 방식으로 동작합니다. 핵심 아이디어는 기존 객체를 수정하지 않고도 새로운 책임을 부여할 수 있다는 점입니다.

구조

  1. Component: 기본 인터페이스 또는 추상 클래스
  2. ConcreteComponent: 실제 기능을 구현한 클래스
  3. Decorator: Component를 확장할 추상 클래스

ConcreteDecorator: 구체적인 기능 확장을 구현한 클래스

출처: 위키


3. 예제

C#에서의 간단한 예제로, 커피에 첨가물을 추가하는 시뮬레이션을 만들어보겠습니다. ☕

// Component
public interface ICoffee
{
    string GetDescription();
    double GetCost();
}

// ConcreteComponent
public class SimpleCoffee : ICoffee
{
    public string GetDescription() => "Simple Coffee";

    public double GetCost() => 2.0;
}

// Decorator
public abstract class CoffeeDecorator : ICoffee
{
    protected ICoffee _coffee;

    public CoffeeDecorator(ICoffee coffee)
    {
        _coffee = coffee;
    }

    public virtual string GetDescription() => _coffee.GetDescription();

    public virtual double GetCost() => _coffee.GetCost();
}

// ConcreteDecorator
public class MilkDecorator : CoffeeDecorator
{
    public MilkDecorator(ICoffee coffee) : base(coffee) { }

    public override string GetDescription() => base.GetDescription() + ", Milk";

    public override double GetCost() => base.GetCost() + 0.5;
}

public class SugarDecorator : CoffeeDecorator
{
    public SugarDecorator(ICoffee coffee) : base(coffee) { }

    public override string GetDescription() => base.GetDescription() + ", Sugar";

    public override double GetCost() => base.GetCost() + 0.2;
}

// Usage
class Program
{
    static void Main(string[] args)
    {
        ICoffee coffee = new SimpleCoffee();
        Console.WriteLine($"{coffee.GetDescription()} : ${coffee.GetCost()}");

        coffee = new MilkDecorator(coffee);
        Console.WriteLine($"{coffee.GetDescription()} : ${coffee.GetCost()}");

        coffee = new SugarDecorator(coffee);
        Console.WriteLine($"{coffee.GetDescription()} : ${coffee.GetCost()}");
    }
}

실행 결과

Simple Coffee : $2.0
Simple Coffee, Milk : $2.5
Simple Coffee, Milk, Sugar : $2.7

4. 장점과 주의점 🛠️

장점

  • 유연성: 객체의 기능을 런타임에 동적으로 확장 가능.
  • 조합 가능성: 다양한 Decorator를 조합해 새로운 기능 생성.
  • OCP(Open/Closed Principle): 기존 코드를 변경하지 않고 기능 추가 가능.

주의점

  • 많은 클래스: Decorator와 ConcreteDecorator가 많아질 경우 복잡도가 증가.
  • 디버깅 어려움: 래핑된 구조로 인해 디버깅이 다소 까다로울 수 있음.

5. 결론

Decorator 패턴은 객체 지향 설계의 유연성을 극대화하는 강력한 도구입니다. 기존 객체를 수정하지 않고 기능을 확장해야 하는 상황에서 매우 유용하며, 특히 계층적 상속의 한계를 극복하는 데 도움을 줍니다. 다만, 과도한 사용은 복잡도를 높일 수 있으니 신중히 활용해야 합니다. ✅


6. 관련 링크

반응형