본문 바로가기

Develop/Design Pattern

[Design Pattern] 데코레이터 (Decorator) 패턴

728x90

1. 개요

  • 데코레이터 디자인 패턴 (Decorator Design Pattern)은 객체에 동적으로 새로운 기능을 추가하기 위한 패턴이다.

이 패턴은 상속이 아닌 객체 래핑(Object Wrapping)하여 새로운 기능을 추가한다.

2. 상황

3. 다이어그램

decorator-default

3.1. 설명

  • Component
    • 기본 기능을 정의하는 인터페이스 이다.
    • DecoratorConcreteDecorator에 의해 구현된다.
  • ConcreteComponent
    • Component의 구현 클래스 이다.
  • Decorator
    • 추상 클래스 이다.
    • Component의 구현 클래스 이면서 Component 인스턴스를 갖고 있다.
    • Component의 메소드를 호출 후 추가적인 동작을 수행한다.
  • ConcreteDecorator
    • Decorator의 구현 클래스로, 추가적인 기능을 구현한다.
    • Component를 래핑하여 새로운 기능을 동적으로 추가할 수 있다.

4. 구현

public interface Component { void operation(); }

public class ConcreteComponent implements Component {
  @Override
  public void operation() {
    System.out.println("Executing operation in ConcreteComponent");
  }
}
public class Decorator implements Component {
  protected Component component;

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

  @Override
  public void operation() { component.operation(); }
}

public class DecoratorA extends Decorator {
  public DecoratorA(Component component) { super(component); }

  @Override
  public void operation() {
    super.operation();
    System.out.println("Executing operation in ConcreteDecoratorA");
  }
}

public class DecoratorB extends Decorator {
  public DecoratorB(Component component) { super(component); }

  @Override
  public void operation() {
    super.operation();
    System.out.println("Executing operation in ConcreteDecoratorB");
  }
}
public class Client {
  public static void main(String[] args) {
    Component concrete = new ConcreteComponent();
    Component decorated = new DecoratorA(new DecoratorB(concrete));

    decorated.operation();
  }
}

출력결과

Executing operation in ConcreteComponent
Executing operation in ConcreteDecoratorB
Executing operation in ConcreteDecoratorA

5. 예시

public interface Weapon { void attack(); }

public class Sword implements Weapon {
  @Override
  public void attack() {
    System.out.println("Slash with sword");
  }
}
public class WeaponDecorator implements Weapon { 
  private Weapon weapon;
  public WeaponDecorator(Weapon weapon) { this.weapon = weapon; }

  @Override
  public void attack() { weapon.attack(); }
}

public class FlameDecorator extends WeaponDecorator { 
  public FlameDecorator(Weapon weapon) { super(weapon); }

  @Override
  public void attack() {
    super.attack();
    System.out.println("  + with flames");
  }
}

public class DurableDecorator extends WeaponDecorator { 
  public DurableDecorator(Weapon weapon) { super(weapon); }

  @Override
  public void attack() {
    super.attack();
    System.out.println("  + with increased durability");
  }
}
public class Client {
  public static void main(String[] args) {
    Weapon sword = new Sword();
    Weapon decoratedSword = new FlameDecorator(new DurableDecorator(sword));

    decoratedSword.attack();
  }
}

출력결과

Slash with sword
  + with increased durability
  + with flames

6. 장단점

6.1. 장점

  • 상속을 통해 기능을 확장하는 것보다 유연성이 높다.
  • 런타임 중 동적으로 기능을 추가하거나 제거할 수 있다.
  • 기능을 조합하여 다양한 방식으로 객체를 구성할 수 있다.
  • 여러 개의 Decorator를 중첩하여 기능을 조합할 수 있다.
  • 개별 기능을 수정하지 않고도 객체의 동작을 확장할 수 있다.

6.2. 단점

  • 코드의 복잡성이 증가한다.
  • Decorator 클래스 간 코드 중복이 발생할 수 있다.

관련 포스팅

728x90