Skip to main content

[Design Pattern] 구조 패턴 1. 데코레이터 (Decorator)




데코레이터 (Decorator) #

데코레이터

  • 동적으로 런타임에 객체에 추가적인 책임을 부여한다.
  • 특징
    • 기능을 확장하기 위한 서브 클래싱의 대안이다. 정적으로 기능을 늘릴 수 있는 상속과 달리, 데코레이터 패턴은 런타임에 객체의 행동이 확장되게 돕는다.



  • 문제점 : 무지막지하게 늘어나는 서브 클래스
public abstract class Beverage
{
    public abstract string GetDesc();
}

public class Espresso : Beverage
{
    public override string GetDesc()
    {
        return "샷 추가";
    }
}

public class ChocolateCoffee : Beverage
{
    public override string GetDesc()
    {
        return "초코 파우더 추가";
    }
}

public class WhippedCreamChocolateCoffee : Beverage
{
    public override string GetDesc()
    {
        return "휘핑과 초코파우더 추가";
    }
}

// ... 계속 이렇게 만들다가는 엄청난 서브 클래스들이 생긴다. 
// 음식의 옵션 별로 따로 두면 좋지 않을까?

  • 해결
// 똑같이 Beverage를 상속하는 데코레이터를 만든다. 
public abstract class BeverageDecorator : Beverage
{
    Beverage beverage;
    
    public BeverageDecorator(Beverage b)
    {
        beverage = b;
    }
    
    public override string GetDesc()
    {
        return beverage.GetDesc();
    }
}

public class Whip : BeverageDecorator
{
    public Whip(Beverage b) : base(b) {}

    public override string GetDesc()
    {
        return base.GetDesc() + ", 휘핑 추가";
    }
}

public class Choco : BeverageDecorator
{
    public Choco(Beverage b) : base(b) {}
    
    public override string GetDesc()
    {
        return base.GetDesc() + ", 초코 추가";
    }
}

class Program
{
    static void Main(string[] args)
    {
        Beverage b = new Espresso();
         
        // 책임을 동적으로 추가할 수 있다.    
        b = new Choco(b);
        b = new Choco(b);
        b = new Whip(b);
        
        Console.WriteLine(b.GetDesc()); // 샷 추가, 초코 추가, 초코 추가, 휘핑 추가 
    }
}



개념적인 예시 #

public abstract class Component
{
    public abstract string Operation();
}

// 컴포넌트를 상속하는 구체화된 컴포넌트
class ConcreteComponent : Component
{
    public override string Operation()
    {
        return "ConcreteComponent";
    }
}

// 컴포넌트를 상속하는 데코레이터
abstract class Decorator : Component
{
    // 컴포넌트를 가지고 있다. 
    protected Component _component;

    public Decorator(Component component)
    {
        this._component = component;
    }

    public void SetComponent(Component component)
    {
        this._component = component;
    }

    public override string Operation()
    {
        if (this._component != null)
        {
            return this._component.Operation();
        }
        else
        {
            return string.Empty;
        }
    }
}

// 구체화된 데코레이터 A
class ConcreteDecoratorA : Decorator
{
    public ConcreteDecoratorA(Component comp) : base(comp)
    {
    }

    public override string Operation()
    {
        return $"ConcreteDecoratorA({base.Operation()})";
    }
}

// 구체화된 데코레이터 B
class ConcreteDecoratorB : Decorator
{
    public ConcreteDecoratorB(Component comp) : base(comp)
    {
    }

    public override string Operation()
    {
        return $"ConcreteDecoratorB({base.Operation()})";
    }
}

public class Client
{
    public void ClientCode(Component component)
    {
        Console.WriteLine(component.Operation());
    }
}

class Program
{
    static void Main(string[] args)
    {
        Client client = new Client();

        var simple = new ConcreteComponent();
        client.ClientCode(simple); 
        // ConcreteComponent


        // 데코레이터로 책임을 추가할 수 있다. 
        ConcreteDecoratorA decorator1 = new ConcreteDecoratorA(simple);
        ConcreteDecoratorB decorator2 = new ConcreteDecoratorB(decorator1);
        client.ClientCode(decorator2);
        // ConcreteDecoratorB(ConcreteDecoratorA(ConcreteComponent))
    }
}



References #