[Design Pattern] 구조 패턴 1. 데코레이터 (Decorator)
Table of Contents
데코레이터 (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))
}
}