데코레이터 패턴

OCP (Open-Closed Principle)

  • 클래스는 확장에 열려있고 변경에는 닫혀있어야 한다.

    • Composition 적극 활용

  • ? 요구사항이나 조건이 바뀌면 확장 확장!

  • 기존 코드를 건드리지 않고 확장으로 새로운 행동을 추가하는 것

확장에는 열려 있고 변경에는 닫혀 있다. 두 가지 조건이 양립할 수 있나?

  • 확장하려고 코드를 직접 수정하는 일을 방지

  • 모순처럼 보이지만, 직접 코드를 수정하지 않고도 코드를 확장해주는 기법들이 존재

모든 부문에 OCP를 준수할 수 있나?

  • 불가능 -많은 시간과 비용 발생, 그렇게 할 필요도 없다.

  • OCP를 지키다 보면 새로운 단계의 추상화가 필요해진다.

  • 추상화를 하다 보면 코드가 복잡해지는데 가장 바뀔 가능성이 높은 부분을 중점적으로 살펴보고 적용

데코레이터 - OCP를 충실히 지키는 패턴

데코레이터 객체를 '래퍼' 객체라고 생각해보자.

객체에 추가 요소를 동적으로 더하는 기능

  • 데코레이터 객체의 형식은 장식하고 있는 객체와 같은 인터페이스를 갖는다.

  • 감싸는 객체에 +@ 새로운 행동을 추가

  • 가장 바깥쪽의 메서드를 호출하면 그 객체가 장식하고 있는 객체에게 계산을 위임한다.

  • 상속 대신 데코레이터!

  • 한 객체에 여러 개의 데코레이터로 감쌀 수 있음 (개수에는 제한 X)

  • 데코레이터는 자신이 감싸고 있는 객체와 같은 슈퍼 클래스를 가지고 있기에 원래 객체(쌓여있는 객체)가 들어갈 자리에 데코레이터 객체를 넣어도 상관없음

  • 데코레이터는 자신이 장식하고 있는 객체에게 어떤 행동을 위임하는 일 말고도 별도 작업을 추가할 수 있다.

  • 객체는 언제든 감쌀수 있으므로 실행 중 필요로하는 데코레이터를 마음대로 적용 가능

    • 상속 써야했다면 행동이 컴파일 시에 정적으로 결정되어 상속받은것과 오버라이딩한것만 쓸 수 있게됨

    • 상속에만 의존했다면 새로운 행동을 추가할 때마다 기존 코드를 바꿔야함

  • 데코레이터를 사용하면 서브 클래스를 만들 때보다 훨씬 유연하게 기능을 확장할 수 있음

public abstract class CondimentDecorator extends Beverage {
  Beverage beverage;
  public abstract String getDescription();
}

public class Mocha extends CondimentDecorator {
  public Mocha(Bevarage beverage) {
    this.beverage = beverage;
  }
  
  public String getDescription() {
    return beverage.getDescription() + ', 모카'
  }
  
  public double cost() {
    return beverage.cost() + .20;
  }
}

단점

  • 데코레이터 패턴을 사용하다보면 잡다한 클래스가 너무 많아짐

  • 클라이언트는 데코레이터를 끼워넣어도 데코레이터를 사용하고 있는지 알 수 없다.

    • 클라이언트가 구성 요소의 구체적인 형식에 의존하는 경우는 예외

  • 너무 많이 사용하면 코드가 필요 이상으로 복잡해짐

Last updated