1. 용도
데코레이터 패턴은 런타임에 다른 객체에 영향을 주지 않고 개개의 객체에 속성이나 책임을 추가하거나 제거해야 할 경우에 유용할 수 있다.
예를 들면 텍스트 편집기에서 Text를 출력하는 창에 옵션에 따라 스크롤 바, 테두리 따위로 장식할 수 있게하고 싶을 때 장식자 패턴을 사용할 수 있다.
2. 구조
장식자 패턴은 간단히 말해서 컴포넌트 객체를 장식 객체로 감싸는 구조다.
일반화된 클래스 다이어그램을 살펴보자. 컴포넌트와 장식자의 관계를 보면 장식자도 컴포넌트에 포함되는 개념이다.
위의 텍스트 뷰(컴포넌트), 테두리(장식), 스크롤 바(장식)의 예를 객체 다이어그램으로 나타내면 아래와 같다.
BorderDecorator 객체가 component로 ScrollDecorator 객체를 가지고, ScrollDecorator 객체가 컴포넌트인 TextView 객체를 가진다. 이런 구조 덕분에 컴포넌트에 많은 장식을 붙일 수 있다. 장식을 추가하고 싶다면 장식 객체를 더 붙이면 된다.
이번엔 클래스 다이어 그램으로 알아보자.
장식 클래스들은 Decorator 클래스를 상속받고, component로 VisaulComponent 객체를 가질 수 있다. 만약 Decorator 클래스의 Draw 함수가 호출되면 그 안에서 자식(component)의 Draw를 호출하는 식으로 동작한다. 그리고 자식 Draw 함수에서는 자신의 기능을 구현하면서 또 자신의 자식 컴포넌트의 Draw를 호출해주면 된다.
3. 장단점
장점
- 상속보다 좋은 융통성 : 객체에 새로운 행동을 추가하는 다른 방법으로는 단순한 상속이 있다. 여기서 단순한 상속이란 TextView에 테두리를 추가하기 위해 TextView를 상속받는 BorderedTextView라는 클래스를 만드는 방법을 말한다. 이런 방식으로도 객체에 새로운 기능을 추가할 수는 있지만, 새로운 기능을 추가할 때마다 새로운 클래스를 만들어야 하므로 기능과 컴포넌트의 종류가 많다면 엄청난 수의 클래스를 만들어야 하므로 비효율적이다. 하지만 장식자 패턴을 사용하면 기존 클래스의 코드 수정 없이 포함할 수 있으므로 효율적이다.
- 그 때 그 때 추가하기 : 이후에 생겨날 새로운 기능들을 미리 생각하지 않고, 그 때 그 때 필요한 기능에 해당하는 장식자 클래스를 만들어갈 수 있습니다.
단점
- 작은 객체들이 많이 생김 : 어떻게 조합되어 기능을 만드는가에 따라 작은 새로운 객체가 계속 만들어짐. 이 작은 객체들을 잘 이해하고 있다면 재정의하기 쉽지만, 아니라면 그 과정이 복잡해짐.
4. 구현 시 주의사항
- Component 클래스는 가볍게 : 모든 참여자들은 Component를 상속 받아야 하므로 Component 클래스는 최대한 가벼운 것이 좋습니다. 즉 정말 필요한 연산만 정의하고 멤버 변수는 없는 것이 좋습니다.
- 포장 변경 vs 속 변경 : 포장을 변경하면 장식자 패턴, 속을 변경하면 전략 패턴입니다. 둘 중 무엇을 선택하면 좋을지 고민해 보아야 합니다. 보통 Component 클래스가 복잡하거나 무겁다면 전략 패턴을 선택하는 것이 좋습니다.
5. 코드
코드는 귀찮아서 일부 생략함.
구조에 대해서는 이미 위에서 설명했으니 사용,세팅 방식에 유의해서 보자.
//컴포넌트 클래스
class VisualComponent{
public:
virtual void Draw();
virtual void Resize();
};
//장식자 클래스
class Decorator : public VisualComponent{
public:
virtual void Draw();
virtual void Resize();
private:
VisualComponent* _component;
};
//concrete 장식자 클래스
class BorderedDecorator : public Decorator{
public:
BorderedDecorator(VisualComponent*, int borderWidth);
virtual void Draw();
virtual void Resize();
private:
void DrawBorder();
private:
int _width;
};
//사용, 세팅 코드
{
Window* window = new Window;
TextView* textView = new TextView;
window->SetContents(
new BorderedDecorator(
new ScrollDecorator(textView),1
)
)
}
'GOF의 DesignPattern' 카테고리의 다른 글
3장 팩토리 메서드 패턴 (0) | 2023.03.02 |
---|---|
3장 빌더 패턴 (0) | 2023.03.01 |
3장. 생성 패턴 & 추상 팩토리 패턴 (0) | 2023.02.27 |
2장 사례 연구: 문서 편집기 설계 (0) | 2023.02.25 |
1장 서론. (0) | 2023.02.07 |