강의 정리/오픈소스sw개발방법및도구

Selects a SINGLE pattern, and surveys [goal, detail, UML, code]: Decorator Pattern

Yo-mi 2023. 8. 31. 03:22

0. Decorator Pattern이란?

 데코레이터 패턴은 객체의 추가적인 요건을 동적으로 추가하는 패턴이다. 중심이 되는 객체가 반환하는 값에 추가적으로 더해져서 결과값을 반환한다.

 

 

1. goal

 데코레이터 패턴은 특정 객체의 기능을 정적으로 확장(장식)하는 데 사용할 수 있다. 하나의 객체에 부가적인 기능을 덧붙여 많은 객체에게 다양한 부가기능을 쉽고 빠르게 적용하는 것이 목표이다. 다시 말해 객체가 동적으로 움직이고 있는 중에 특정 기능을 추가하고 뺄 수 있도록 하는 것이다.

 

 

2. Detail

 중심이 되는 객체를 놔두고 추가적인 사항을 첨가하는 방식이라 객체에 기능을 추가 또는 삭제할 때 중심이 되는 객체를 수정하지 않고 동적으로 추가 또는 삭제할 수 있다는 장점이 있다. 객체 지향의 원칙 중 확장에는 열려 있고 변경에는 닫혀 있어야 한다는 원칙인 OCP(Open-Close Principle)에 충실한 패턴이다. 데코레이터 패턴을 사용하게 되면 기존 객체는 변경하지 않고 자유로운 확장을 구현할 수 있으며 기존 객체 혹은 데코레이터가 수정되더라도 해당 클래스의 내용만 수정해주면 되기 때문에 변경에 대해서도 닫혀 있다. 또한 기본적인 데이터에 첨가하는 데이터가 일정하지 않고 다양할 때 데코레이터 패턴을 사용하면 효율적으로 사용할 수 있다. 반면에 데코레이터를 너무 많이 사용하게 되면 자잘한 객체가 많이 추가될 수 있고 오히려 코드가 복잡해질 수 있다는 단점이 있다.

 

[상속과의 차이점]

상속은 하위 클래스를 생성하는 방법으로 확장을 하며 데코레이터 패턴은 기본 객체에 추가하는 객체를 생성하는 방법으로 확장을 한다. 상속은 오버라이딩을 통해 기능을 전부 명시해 줘야 하지만 데코레이터 패턴은 기본 기능은 놔두고 추가되는 기능만 명시해 줄 수 있다는 차이가 있다.

 

[Composite 패턴과 차이점]

다양하고 일정하지 않은 여러 객체들을 하나의 객체로 묶는 것을 Composite 패턴이라고 한다. Composite 패턴은 목적이 생성되어 있는 객체들 간의 합성에 있고 데코레이터 패턴은 목적이 객체에 새로운 행동을 추가하는 데에 있다.

 

[Strategy 패턴과의 차이점]

Strategy 패턴은 유사한 행위를 캡슐화하는 인터페이스를 정의하여 객체들의 행위를 유연하게 확장하는 방법이다. Strategy 패턴은 객체의 내부를 변화시키며 데코레이터 패턴은 새로운 객체를 추가하여 객체를 변경시킨다는 점에서 차이가 있다.

 

 

3. UMLs

Component: 동적으로 추가할 객체들의 인터페이스 역할을 한다.

 

ConcreteComponent: 제공할 서비스의 베이스가 되는 컴포넌트를 정의한다.

 

Decorator: Component 객체에 대한 참조자를 관리(인스턴스 변수로 소유)하면서 Component에 정의된 인터페이스를 만족하도록 인터페이스를 정의한다.

 

ConcreteDecoreator: Component에 추가할 내용을 구체적으로 구현한다.

 

 

 

 

 

 

 

4.     Code Example

 위젯을 그리는 프로그램을 만든다고 가정하고 여러가지 위젯 중 캘린더 위젯을 만들고 위젯은 Scroller, Boarder로 구성할 수 있다.

[Component]

class WidgetComponent {

public:

    virtual void Draw() = 0;

};

 

[ConcreteComponent]

class CalendarWidget: public WidgetComponent {

public:

    virtual void Draw() {

        cout<<"Draw Window"<<endl;

    }

};

 

[Decorator]

class Decorator: public WidgetComponent {

public:

    Decorator(WidgetComponent* comp): component(comp){};

   

    virtual void Draw() {

        component->Draw();

    }

   

private:

    WidgetComponent* component;

};

 

[ConcreteDecorator]

class BorderDecorator: public Decorator {

public:

    BorderDecorator(WidgetComponent* comp)

    :Decorator(comp){}

   

    virtual void Draw() {

        Decorator::Draw();

        DrawBoarder();

    }

   

private:

    void DrawBoarder() {

        cout<<"Draw Boarder"<<endl;

    }

};

 

class ScrollDecorator: public Decorator {

public:

    ScrollDecorator(WidgetComponent* comp)

    :Decorator(comp){}

   

    virtual void Draw() {

        Decorator::Draw();

        DrawScroll();

    }

   

private:

    void DrawScroll() {

        cout<<"Draw Scroll"<<endl;

    }

};

 

[실행]

int main(int argc, const char * argv[]) {

    WidgetComponent* widget = new CalendarWidget();

    widget = new BorderDecorator(widget);

    widget = new ScrollDecorator(widget);

   

    widget->Draw();

   

    return 0;

}

 

[실행 결과]

Draw Window

Draw Boarder

Draw Scroll