데코레이터 패턴은 구조를 변경하지 않고도 객체에 새로운 기능을 동적으로 추가할 수 있는 구조적 디자인 패턴입니다. 이는 기존 클래스를 직접 수정하지 않고도 기존 클래스의 동작을 확장할 수 있는 유연한 방법을 제공합니다.
주요 구성
- 구성 요소: 특정 작업을 수행할 수 있는 개체에 대한 인터페이스 또는 추상 클래스를 정의합니다. 추가 기능으로 향상시키려는 대상 개체를 나타냅니다.
- ConcreteComponent: Component 인터페이스를 구현하는 실제 클래스입니다. 기본적인 기능을 제공합니다.
- 데코레이터: 이는 Component 인터페이스를 구현하고 Component 객체에 대한 참조를 보유합니다. 원본 개체를 래핑하여 새로운 동작을 추가합니다.
- ConcreteDecorator: Decorator 클래스를 확장하고 특정 기능이나 수정 사항을 추가합니다.
Code
일반 텍스트를 표시할 수 있는 간단한 문자 메시지 개체를 고려해 보겠습니다. 이제 이 메시지에 HTML 태그, 암호화 또는 네트워크 전송을 추가하려면 각 기능에 대해 별도의 데코레이터를 만들 수 있습니다. 필요에 따라 이러한 데코레이터를 결합하여 원본 메시지 개체를 향상시킬 수 있습니다.
IComponent.cs
// 'Component' interface
public interface IComponent
{
string Operation();
}
C#ConcreteComponent.cs
// 'ConcreteComponent' class
public class ConcreteComponent : IComponent
{
public string Operation()
{
return "ConcreteComponent";
}
}
C#Decorator.cs
// 'Decorator' 추상 class
public abstract class Decorator : IComponent
{
protected IComponent _component;
public Decorator(IComponent component)
{
_component = component;
}
public virtual string Operation()
{
return _component.Operation();
}
}
C#ConcreteDecoratorA.cs
// 'ConcreteDecoratorA' class
public class ConcreteDecoratorA : Decorator
{
public ConcreteDecoratorA(IComponent component) : base(component)
{
}
public override string Operation()
{
return $"ConcreteDecoratorA({base.Operation()})";
}
}
C#ConcreteDecoratorB.cs
// 'ConcreteDecoratorB' class
public class ConcreteDecoratorB : Decorator
{
public ConcreteDecoratorB(IComponent component) : base(component)
{
}
public override string Operation()
{
return $"ConcreteDecoratorB({base.Operation()})";
}
}
C#Program.cs
// Create basic component
IComponent component = new ConcreteComponent();
Console.WriteLine("Basic Component: " + component.Operation());
// Decorated with A
IComponent decoratedComponentA = new ConcreteDecoratorA(component);
Console.WriteLine("Decorated with A: " + decoratedComponentA.Operation());
// Decorated with B
IComponent decoratedComponentB = new ConcreteDecoratorB(component);
Console.WriteLine("Decorated with B: " + decoratedComponentB.Operation());
// Decorated with A and B
IComponent decoratedComponentAB = new ConcreteDecoratorB(decoratedComponentA);
Console.WriteLine("Decorated with A and B: " + decoratedComponentAB.Operation());
C#Results:
요약
데코레이터 패턴은 프로토타입을 사용하는 JavaScript와 같은 언어에서 특히 유용하며 C#과 같은 클래스 기반 언어에서도 디자인 유연성을 제공합니다. 이를 통해 특히 런타임에 기능을 추가하거나 수정해야 할 때 개체 기능을 동적으로 확장할 수 있습니다.
데코레이터 패턴의 장점
- 기존 코드를 변경하지 않고 새로운 기능을 추가합니다.
- 복잡한 기능을 위해 여러 데코레이터를 구성할 수 있습니다.
- 상속보다 더 많은 유연성을 제공합니다.
단점
- 다수의 작은 개체가 발생하여 시스템 복잡성이 증가할 수 있습니다.
- 구성 요소와 데코레이터 간의 관계를 이해하는 것은 어려울 수 있습니다.
이러한 장단점을 고려하면 데코레이터 패턴은 객체 동작의 동적 확장이나 수정이 필요한 상황에 가장 적합합니다.