본문 바로가기

Design Pattern

[Design pattern] DECORATOR


패턴

- 장식자(DECORATOR)

 

의도

- 객체에 동적으로 새로운 책임을 추가할 수 있게 한다. 기능을 추가하려면, 서브 클래스를 생성하는 것보다 융통성 있는 방법을 제공한다.

 

다른 이름

- 랩퍼(Wrapper)

 

동기

- 가끔 전체 클래스에 새로운 기능을 추가할 필요는 없지만, 개별적인 객체에 새로운 책임을 추가할 필요가 있다. 예를 들어, GUI툴킷에서 모든 사용자 인터페이스 요소에는 필요 없지만, 어떤 사용자 인터페이스 요소에만 스크롤링(scroling)과 같은 행동이나 테두리(border)와 같은 속성을 추가할 수 있도록 해 줄 필요는 있다. 이런 것은 하나의 객체에 속성이 추가됨으로써 또 다른 책임이 추가되어야 한다.

 

하지만, 이 같은 방법은 테두리의 선택이 정적이기 때문에, 사용자는 구성요소를 언제, 그리고 어떻게 테투리를 장식해야 할지 제어할 수 없다. 더 나은 방법은 지금 필요한 테두리를 추가하는 다른 객체에다가 해당 구조요소를 둘러싸는 것입니다. 이렇게 무엇인가를 감싸는 객체를 장식자(decorator)라고 한다.

 

구조도

활용성

1. 동적으로 또한 투명하게(transparent), 다시 말해 다른 객체에 영향을 주지 않고 개개의 객체에 새로운 책임을 추가하기 위해 사용.

2. 제거될 수 있는 책임에 대해 사용한다.

3. 실제 상속으로 서브클래스를 계속 만드는 방법이 실질적이지 못할 때 사용.

 

결과

1. 단순한 상속보다 설계의 융통성을 더 많이 증대시킬 수 있다.

2. 클래스 계통의 상부측 클래스에 많은 기능이 누적되는 상황을 피할 수 있다.

3. 장식자와 해당 그 장식자의 구성요소가 동일한 것은 아니다.

4. 장식자를 사용함으로써 작은 규모의 객체들이 많이 생긴다.

 

예제.

 

1. Visual-Component란 이름의 구성 요소 클래스가 있다고 가정한다.

 

class VisualComponent

{

public : VisualComponent();

virtual void Draw();

virtual void Resize();

//...

};

2. VisualComponent의 서브 클래스로 Decorator를 정의한다. 다른 장식을 만들려면 VisualComponent를 상속받는 다른 서브클래스를 정의하면 된다.

class Decorator : public VisualComponent

{

public : Decorator(VisualComponent*);

virtual void Draw();

virtual void Resize();

//...

private :

VisualComponent* _component;

};

- Decorator 클래스는 _component라는 내부 변수로 참조되는 Visual-Component 클래스를 장식합니다. _component는 생성자에서 초기화된다.

- Decorator는 자신이 관리하는 VisualComponent에 대한 참조자를 이용하여, 실제로 VisualComponent에 정의된 각 연산의 기능이 필요하면

_component->연산()과 같은 호출을 통해 VisualComponent에 요청을 전달한다.

- 하지만 실제로 코드상으로는 VisualComponent 클래스에 메시지를 보내는 것으로 보이나, 실제로 실행될 때는 VisualComponent 클래스의

서브 클래스 중 어느 하나의 인스턴스를 참조하게 되는데, 이것이 누구인가에 따라서 어떤 클래스의 연산이 호출될지는 모른다.

 

void Decorator::Draw()

{

_component->Draw();

}

void Decorator::Resize()

{

_component->Resize();

}

- Decorator의 서브클래스는 새로운 기능에 대한 구현 방법을 정의한다. Border-Decorator는 자신이 포함하는 요소에 테두리를 추가하기 위해 Decorator

클래스를 상속받아 부모 클래스의 Draw() 연산을 재정의한다. BorderDecorator 클래스에 정의된 DrawBorder() 연산은 private로 정의하여 실제 그리기 기능을

담당하게 된다. private로 정의하는 이유는 실제 BorderDecorator를 사용하는 클래스가 VisualComponent에 정의된 연산만을 인터페이스로 바라보고 요청할 뿐,

추가된 Deorator 서브클래스에 정의된 연산을 직접 호출할 수 없도록 하려는 것이다. 새롭게 추가된 연산은 단지 새로운 기능 구현에 필요한 내용을 담고 있고,

Decorator에 정의된 연산의 재정의 과정에서 내부적으로만 호출되기 때문에 private로 정의한다.

3. Decorator 서브 클래스는 Decorator에 정의된 모든 구현을 상속 받는다.

class BoraderDecoraor : public Decorator

{

public:

BoraderDecoraor(VisualComponent*, int borderWidth);

virtual void Draw();

private:

void DrawBorder(int);

private:

int _width;

};

void BorderDecorator::Draw()

{

Decorator::Draw(); DrawBoder(_width);

}

- 이와 같은 방법으로 ScrollDecorator 클래스와 DropShadowDecorator 클래스를 개발할 수 있다.

 

 

'Design Pattern' 카테고리의 다른 글

[Design pattern] Singleton Pattern with C++ 11  (0) 2015.07.29
[Design pattern] 반복자 Iterator  (0) 2013.02.25
[Design pattern] 복합체 Composite  (0) 2013.02.25
[Design pattern] 감시자 Observer  (0) 2013.02.25
[Design pattern] Bridge  (0) 2013.02.21