[C/C++] 데코레이터 패턴(Decorator Pattern)

할랑말랑·2026년 3월 23일

C/C++

목록 보기
35/45

데코레이터 패턴(Decorator Pattern)

기존 객체의 동작을 수정하지 않고, 객체에 동적으로 기능을 추가하는 패턴

1. 특징

  • 동적 확장 : 실행 시간(Runtime)에 객체의 기능을 추가/제거 가능
  • SRP : 커다란 클래스 하나에 모든 기능을 넣는 대신, 기능을 여러 데코레이터 클래스로 분리하여 관리

2. 구성 요소

  • Component : 기능을 추가할 객체들의 공통 인터페이스
  • ConcreteComponent : 기본 기능을 구현한 실제 클래스
  • Decorator : Component와 ConcreteDecorator를 동일시 하도록 해주는 역할
  • ConcreteDecoreator : 실질적인 장식 인스턴스 및 정의이며 추가된 책임의 주체

3. 장점

  • 상속 없이 기능 확장
  • 런타임에 동적으로 추가/제거
  • 단일 책임 원칙 (SRP)

4. 단점

  • 작은 객체가 많아짐
  • 디버깅 어려움
  • 제거가 어려움

Decorator Pattern : 무기 강화

#include <iostream>
#include <memory>
#include <string>

// 기능을 추가할 대상이 되는 객체들의 공통 인터페이스
class Component
{
public:
    virtual ~Component() = default;
    virtual std::string GetName() const = 0;
    virtual int Attack() = 0;
};

// 기본 기능을 제공하는 구체적인 클래스 (Concrete Component)
class Sword : public Component
{
private:
    std::string name;
    int attack;
public:
    Sword(const std::string& _name = "Sword", int _attack = 10) : name(_name), attack(_attack) {}
    std::string GetName() const override { return name; }
    int Attack() override
    {
        return attack;
    }
};

// 모든 데코레이터들의 부모 클래스. Component를 상속받음. (Decorator)
class Decorator : public Component
{
protected:
    std::unique_ptr<Component> item; // 감쌀(Wrapping) 대상이 되는 Component
public:
    Decorator(std::unique_ptr<Component> _item) : item(std::move(_item)) {}
    std::string GetName() const override
    {
        // 기본적으로는 감싸고 있는 대상의 기능을 그대로 호출
        return item->GetName();
    }
    int Attack() override
    {
        // 기본적으로는 감싸고 있는 대상의 기능을 그대로 호출
        return item->Attack();
    }
};

// 구체적인 기능을 추가하는 데코레이터 클래스 (Concrete Decorator)
class Enhancement : public Decorator
{
private:
    int addattack;
public:
    Enhancement(std::unique_ptr<Component> _comp, int _addattack = 10)
        : Decorator(std::move(_comp)), addattack(_addattack) {}

    // 감싸고 있는 대상의 GetName() 결과에 "+"를 추가하여 반환
    std::string GetName() const override
    {
        return Decorator::GetName() + "+";
    }

    // 감싸고 있는 대상의 Attack() 결과에 자신의 공격력을 더하여 반환
    int Attack() override
    {
        return Decorator::Attack() + addattack;
    }
};

int main()
{
    // 1. 기본 Sword 객체 생성
    std::unique_ptr<Component> sword = std::make_unique<Sword>();
    std::cout << "이름 : " << sword->GetName() << std::endl;
    std::cout << "공격력 : " << sword->Attack() << std::endl;

    // 2. Sword 객체를 Enhancement 데코레이터로 감싸서 강화
    sword = std::make_unique<Enhancement>(std::move(sword));
    // 3. 강화된 Sword를 또다시 Enhancement 데코레이터로 감싸서 2차 강화
    sword = std::make_unique<Enhancement>(std::move(sword));

    std::cout << "이름 : " << sword->GetName() << std::endl;
    std::cout << "공격력 : " << sword->Attack() << std::endl;

    return 0;
}

  • 동일한 인터페이스 : 기본 객체(Sword)와 데코레이터(Enhancement)가 모두 같은 인터페이스(Component)를 구현, 이 덕분에 데코레이터로 감싸진 객체도 원래 객체와 동일한 방식으로 사용할 수 있다.
  • 객체 감싸기(Wrapping) : Decorator 클래스는 내부에 Component 포인터를 가지고, 생성자를 통해 꾸며줄 대상 객체를 받는다. Enhancement는 이 Decorator를 상속받아 구체적인 꾸미기 로직을 구현
  • 동적 기능 추가 : main 함수에서 볼 수 있듯이, sword 포인터에 Enhancement로 감싼 새로운 객체를 계속 대입하는 것만으로도 기능(이름에 + 추가, 공격력 증가)이 동적으로 계속 추가할수있다.

0개의 댓글