데코레이터(Decorator)

Seo·2020년 8월 26일
0

design_pattern

목록 보기
11/11

상위문서: GoF 디자인 패턴

데코레이터(Decorator)

  • 상위 Category : 구조(Structural) 패턴

객체에 동적으로 새로운 책임(responsibility)을 추가할 수 있게 하는 패턴
서브클래스를 생성하는 것보다 융통성 있는 방법을 제공한다.

예를 들어, GUI 툴킷에 모든 사용자 인터페이스 요소에는 필요 없지만, 특정 인터페이스 요소에만 스크롤링과 같은 행동이나 또는 테두리 속성을 추가할 수 있도록 해줄 필요가 있을 때.

  • 대표적인 방법은 상속이 있다.
    그러나 별로 유용하지 않다. 정적으로 정해지기 때문에 사용자가 언제, 어떻게 테두리로 장식해야 할지 제어할 수 없다.
  • 더 나은 방법은 테두리를 추가하는 다른 객체에다가 해당 구성요소를 둘러싸는 것(wrapping)이다. 이 때 무엇인가를 감싸는 객체를 decorator라고 한다.

언제 사용하는가?

  • 객체 타입과 호출 가능한 메소드를 그대로 유지하면서 객체에 새로운 책임을 추가할 때 사용
  • 탈부착 가능한 책임을 정의할 때 사용
  • 상속을 통해 서브클래스를 계속 만드는 방법이 비효율적일 때 사용

주의점

  • Component는 장식을 추가할 베이스가 되는 역할이므로 작고 가볍게 정의
    가급적 인터페이스만을 정의한다.
    변수는 정의하지 않는다.
    저장할 것이 있다면 서브클래스에서 하자.
  • 상속 구조를 통해 Decorator와 Component가 같은 인터페이스를 갖게 해야 한다.
  • 구현하려는 내용이 객체의 겉은 변경하려는 것인지, 속을 변경하려는 것인지 생각해 보자.
    속을 변경하려는 것이라면 strategy-pattern을 선택하는 것이 더 적절할 수 있다.
  • 데코레이터 패턴이 까답롭다면 다음 패턴을 사용해 제공하는 것을 고려해보자.
    builder-pattern
    factory-pattern
    static-factory-method-pattern

예시

이 예제는 음료(component)와 첨가물(decorator) 조합의 구현을 데코레이터 패턴으로 해결하고 있다.

// 음료
abstract class Beverage {
    String description = "제목 없음";

    public String getDescription() { return description; }
    public abstract double cost();

    @Override
    public String toString() {
        return getDescription() + ": $" + cost();
    }
}

// 첨가물
abstract class CondimentDecorator extends Beverage {
    public abstract String getDescription();
}

다음은 베이스가 되는 두 가지 음료이다.

class Espresso extends Beverage {
    public Espresso() { description = "에스프레소"; }

    @Override
    public double cost() { return 1.99; }
}

class HouseBlend extends Beverage {
    public HouseBlend() { description = "하우스 블렌드 커피"; }

    @Override
    public double cost() { return 0.89; }
}

다음은 모카 첨가물. 이 외에도 두유, 휘핑 크림 등 다양한 첨가물을 만들 수 있다.

class Mocha extends CondimentDecorator {
    Beverage beverage;

    public Mocha(Beverage beverage) {
        description = "모카";
        this.beverage = beverage;
    }

    @Override
    public double cost() {
        // 중요한 부분
        return 0.20 + beverage.cost();
    }

    @Override
    public String getDescription() {
        // 중요한 부분
        return beverage.getDescription() + ", " + description;
    }
}

사용 시에

Beverage beverage = new Espresso();
System.out.println(beverage);

beverage = new Mocha(beverage);
System.out.println(beverage);

Beverage beverage2 = new HouseBlend();
System.out.println(beverage2);

beverage2 = new Mocha(beverage2);
System.out.println(beverage2);

결과

에스프레소: $1.99
에스프레소, 모카: $2.19
하우스 블렌드 커피: $0.89
하우스 블렌드 커피, 모카: $1.09

대표 예시

java.io 패키지에서 데코레이터 패턴을 사용한다.

profile
개발관심자

0개의 댓글