기존 객체의 동작을 수정하지 않고, 객체에 동적으로 기능을 추가하는 패턴
#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로 감싼 새로운 객체를 계속 대입하는 것만으로도 기능(이름에 + 추가, 공격력 증가)이 동적으로 계속 추가할수있다.