Post

Decorator Pattern

데코레이터 패턴에 대해 정리합니다.

Decorator Pattern

개요

  • 상속이 아닌 위임을 통해 객체에 새로운 기능을 추가하는 패턴.

    상속을 이용한 기능 확장은 다양한 조합이 필요한 경우 클래스 수가 불필요하게 증가할 수 있다. 이러한 문제를 해결하기 위해 데코레이터 패턴을 사용한다.

사용하는 경우

  • 객체에 동적으로 새로운 기능을 추가하고 싶은 경우
  • 상속을 통해 기능을 확장하는 것이 적절하지 않은 경우
  • 객체의 기능을 동적으로 확장하고 제거하고 싶은 경우

구성요소

  • Component: 기능을 추가할 대상이 되는 인터페이스
  • ConcreteComponent: 기능을 추가할 대상이 되는 클래스
  • Decorator: Component를 상속받아 기능을 추가할 수 있는 클래스
  • ConcreteDecorator: Decorator를 상속받아 기능을 추가하는 클래스

Decorator Pattern

출처: Decorator Pattern - Wikipedia

예제

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#include <iostream>
#include <memory> // 스마트 포인터 사용

using namespace std;

class Component {
public:
    virtual void operation() = 0;
    virtual ~Component() = default; // 가상 소멸자 추가 (메모리 릭 방지)
};

class ConcreteComponent : public Component {
public:
    void operation() override {
        cout << "ConcreteComponent::operation" << endl;
    }
};

class Decorator : public Component {
protected:
    unique_ptr<Component> component; // 스마트 포인터 사용

public:
    Decorator(unique_ptr<Component> comp) : component(move(comp)) {}

    void operation() override {
        component->operation();
    }
};

class ConcreteDecoratorA : public Decorator {
public:
    ConcreteDecoratorA(unique_ptr<Component> comp) : Decorator(move(comp)) {}

    void operation() override {
        cout << "ConcreteDecoratorA::operation" << endl;
        Decorator::operation();
    }
};

class ConcreteDecoratorB : public Decorator {
public:
    ConcreteDecoratorB(unique_ptr<Component> comp) : Decorator(move(comp)) {}

    void operation() override {
        cout << "ConcreteDecoratorB::operation" << endl;
        Decorator::operation();
    }
};

int main() {
    unique_ptr<Component> delegate = make_unique<ConcreteComponent>();
    
    unique_ptr<Component> decorator = make_unique<ConcreteDecoratorA>(
        make_unique<ConcreteDecoratorB>(move(delegate))
    );

    decorator->operation();

    // 출력:
    // ConcreteDecoratorB::operation
    // ConcreteDecoratorA::operation
    // ConcreteComponent::operation
    return 0;
}

데코레이터 패턴의 장단점

  • 장: 상속을 통해 기능을 확장하는 것보다 유연하게 기능을 추가할 수 있다.
  • 단: 사용자 입장에서 데코레이터 객체와 실제 객체의 구분이 되지 않기 때문에 코드만으로 기능이 어떻게 동작하는지 파악하기 어렵다.
This post is licensed under CC BY 4.0 by the author.