๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
๋””์ž์ธํŒจํ„ด

[๋””์ž์ธํŒจํ„ด] ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ํŒจํ„ด

by ์„œ์•„๋ž‘๐Ÿ˜ 2024. 8. 23.

 


๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ํŒจํ„ด (Decorator Pattern)

๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ํŒจํ„ด์€ ๊ฐ์ฒด ์ง€ํ–ฅ ๋””์ž์ธ ํŒจํ„ด ์ค‘ ํ•˜๋‚˜๋กœ, ๊ฐ์ฒด์— ๋™์ ์œผ๋กœ ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋Š” ๊ตฌ์กฐ๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์ด ํŒจํ„ด์€ ๊ธฐ์กด์˜ ํด๋ž˜์Šค๋ฅผ ์ˆ˜์ •ํ•˜์ง€ ์•Š๊ณ ๋„ ๊ฐ์ฒด์— ์ถ”๊ฐ€์ ์ธ ์ฑ…์ž„์„ ๋ถ€์—ฌํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค๋‹ˆ๋‹ค. ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ํŒจํ„ด์€ ์ƒ์† ๋Œ€์‹  ์กฐํ•ฉ(composition)์„ ํ†ตํ•ด ๊ธฐ๋Šฅ์„ ํ™•์žฅํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์ œ์‹œํ•˜๋ฉฐ, ์ด๋Š” ๊ฐ์ฒด ์ง€ํ–ฅ ์„ค๊ณ„์˜ ๊ฐœ๋ฐฉ-ํ์‡„ ์›์น™(Open-Closed Principle)์„ ์ค€์ˆ˜ํ•˜๋Š” ๋Œ€ํ‘œ์ ์ธ ์˜ˆ์ž…๋‹ˆ๋‹ค.

1. ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ํŒจํ„ด์˜ ๊ธฐ๋ณธ ๊ฐœ๋…

  • ๊ตฌ์„ฑ ์š”์†Œ:
    1. ์ปดํฌ๋„ŒํŠธ(Component): ๊ธฐ๋ณธ ์ธํ„ฐํŽ˜์ด์Šค๋‚˜ ์ถ”์ƒ ํด๋ž˜์Šค์ด๋ฉฐ, ๊ตฌ์ฒด์ ์ธ ๊ฐ์ฒด๋“ค์ด ์ด๋ฅผ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค.
    2. ์ฝ˜ํฌ๋ฆฌํŠธ ์ปดํฌ๋„ŒํŠธ(Concrete Component): ์‹ค์ œ ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•œ ํด๋ž˜์Šค์ž…๋‹ˆ๋‹ค. ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์— ์˜ํ•ด ์žฅ์‹๋  ๊ฐ์ฒด์ž…๋‹ˆ๋‹ค.
    3. ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ(Decorator): Component ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•˜๋ฉฐ, Concrete Component ๊ฐ์ฒด๋ฅผ ๊ฐ์‹ธ์„œ ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.
    4. ์ฝ˜ํฌ๋ฆฌํŠธ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ(Concrete Decorator): ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์˜ ๊ตฌ์ฒด์ ์ธ ๊ตฌํ˜„์ฒด๋กœ, ์ถ”๊ฐ€์ ์ธ ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•˜๊ณ  ์ด๋ฅผ ์›๋ž˜ ๊ฐ์ฒด์— ์œ„์ž„ํ•ฉ๋‹ˆ๋‹ค.
  • ์žฅ์ :
    • ๋Ÿฐํƒ€์ž„์— ๊ฐ์ฒด์— ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์„ ๋™์ ์œผ๋กœ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
    • ์ƒ์†์„ ๋‚จ๋ฐœํ•˜์ง€ ์•Š์œผ๋ฉด์„œ๋„ ๊ฐ์ฒด์˜ ๊ธฐ๋Šฅ์„ ํ™•์žฅํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
    • ํด๋ž˜์Šค ๊ณ„์ธต์˜ ๋ณต์žก์„ฑ์„ ์ค„์—ฌ์ค๋‹ˆ๋‹ค.
  • ๋‹จ์ :
    • ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๊ฐ€ ์—ฌ๋Ÿฌ ๊ฐœ ์ค‘์ฒฉ๋˜๋ฉด ๋ณต์žก๋„๊ฐ€ ์ฆ๊ฐ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
    • ๊ฐ์ฒด์˜ ๊ตฌ์„ฑ(decorator chain)์ด ๋ณต์žกํ•ด์ง€๋ฉด, ๋””๋ฒ„๊น…์ด ์–ด๋ ค์›Œ์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

2. ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ํŒจํ„ด ์˜ˆ์ œ

์•„๋ž˜ ์˜ˆ์ œ์—์„œ๋Š” ์ปคํ”ผ๋ฅผ ๋งŒ๋“œ๋Š” ์‹œ์Šคํ…œ์—์„œ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ํŒจํ„ด์„ ์ ์šฉํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ๊ธฐ๋ณธ์ ์ธ ์ปคํ”ผ(ConcreteComponent)์— ์ถ”๊ฐ€์ ์ธ ์žฌ๋ฃŒ(์˜ˆ: ์šฐ์œ , ์„คํƒ• ๋“ฑ)๋ฅผ ๋™์ ์œผ๋กœ ์ถ”๊ฐ€ํ•˜๋Š” ๊ธฐ๋Šฅ์„ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ํ†ตํ•ด ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค.(C++)

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

// Component
class Coffee {
public:
    virtual std::string getDescription() const = 0;
    virtual double cost() const = 0;
    virtual ~Coffee() = default;
};

// ConcreteComponent
class SimpleCoffee : public Coffee {
public:
    std::string getDescription() const override {
        return "Simple Coffee";
    }

    double cost() const override {
        return 2.0;
    }
};

// Decorator
class CoffeeDecorator : public Coffee {
protected:
    std::unique_ptr<Coffee> decoratedCoffee;

public:
    CoffeeDecorator(std::unique_ptr<Coffee> coffee) : decoratedCoffee(std::move(coffee)) {}

    std::string getDescription() const override {
        return decoratedCoffee->getDescription();
    }

    double cost() const override {
        return decoratedCoffee->cost();
    }
};

// ConcreteDecorator
class MilkDecorator : public CoffeeDecorator {
public:
    MilkDecorator(std::unique_ptr<Coffee> coffee) : CoffeeDecorator(std::move(coffee)) {}

    std::string getDescription() const override {
        return decoratedCoffee->getDescription() + ", Milk";
    }

    double cost() const override {
        return decoratedCoffee->cost() + 0.5;
    }
};

// ConcreteDecorator
class SugarDecorator : public CoffeeDecorator {
public:
    SugarDecorator(std::unique_ptr<Coffee> coffee) : CoffeeDecorator(std::move(coffee)) {}

    std::string getDescription() const override {
        return decoratedCoffee->getDescription() + ", Sugar";
    }

    double cost() const override {
        return decoratedCoffee->cost() + 0.3;
    }
};

int main() {
    // ๊ธฐ๋ณธ ์ปคํ”ผ ์ƒ์„ฑ
    std::unique_ptr<Coffee> myCoffee = std::make_unique<SimpleCoffee>();
    std::cout << myCoffee->getDescription() << " $" << myCoffee->cost() << std::endl;

    // ์šฐ์œ  ์ถ”๊ฐ€
    myCoffee = std::make_unique<MilkDecorator>(std::move(myCoffee));
    std::cout << myCoffee->getDescription() << " $" << myCoffee->cost() << std::endl;

    // ์„คํƒ• ์ถ”๊ฐ€
    myCoffee = std::make_unique<SugarDecorator>(std::move(myCoffee));
    std::cout << myCoffee->getDescription() << " $" << myCoffee->cost() << std::endl;
    
    // ํ•œ๋ฒˆ์— ๋ชจ๋‘ ์ƒ์„ฑ
		std::unique_ptr<Coffee> myCoffee2 = 
				std::make_unique<SugarDecorator>(
						std::make_unique<MilkDecorator>(
								std::make_unique<SimpleCoffee>()));
		std::cout << myCoffee2->getDescription() << " $" << myCoffee2->cost() << std::endl;
		
		return 0;
}
Simple Coffee $2
Simple Coffee, Milk $2.5
Simple Coffee, Milk, Sugar $2.8
Simple Coffee, Milk, Sugar $2.8

3. ์ฝ”๋“œ ์„ค๋ช…

  1. Component: Coffee ์ธํ„ฐํŽ˜์ด์Šค๋Š” ์ปคํ”ผ์˜ getDescription๊ณผ cost ๋ฉ”์„œ๋“œ๋ฅผ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค.
  2. ConcreteComponent: SimpleCoffee ํด๋ž˜์Šค๋Š” ๊ธฐ๋ณธ ์ปคํ”ผ์˜ ์„ค๋ช…๊ณผ ๊ฐ€๊ฒฉ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.
  3. Decorator: CoffeeDecorator ํด๋ž˜์Šค๋Š” Coffee๋ฅผ ์ƒ์†๋ฐ›์•„ ์ปคํ”ผ๋ฅผ ์žฅ์‹ํ•˜๋Š” ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค. ์ด ํด๋ž˜์Šค๋Š” ๊ตฌ์„ฑ๋œ ์ปคํ”ผ ๊ฐ์ฒด๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์œผ๋ฉฐ, ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ํด๋ž˜์Šค๋Š” ์ด ๊ฐ์ฒด์— ์ถ”๊ฐ€์ ์ธ ๊ธฐ๋Šฅ์„ ๋ง๋ถ™์ž…๋‹ˆ๋‹ค.
  4. ConcreteDecorator: MilkDecorator์™€ SugarDecorator๋Š” CoffeeDecorator๋ฅผ ์ƒ์†๋ฐ›์•„ ์šฐ์œ ์™€ ์„คํƒ•์„ ์ถ”๊ฐ€ํ•˜๋Š” ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค.

์ด ์˜ˆ์ œ์—์„œ ์ปคํ”ผ์— ์šฐ์œ ์™€ ์„คํƒ•์„ ์ถ”๊ฐ€ํ•˜๋ฉด์„œ๋„, ์›๋ž˜์˜ SimpleCoffee ํด๋ž˜์Šค๋Š” ์ˆ˜์ •ํ•˜์ง€ ์•Š๊ณ  ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ์ด์ฒ˜๋Ÿผ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ํŒจํ„ด์€ ๊ฐ์ฒด์— ๊ธฐ๋Šฅ์„ ๋™์ ์œผ๋กœ ์ถ”๊ฐ€ํ•˜๋Š” ๋ฐ ๋งค์šฐ ์œ ์šฉํ•œ ํŒจํ„ด์ž…๋‹ˆ๋‹ค.

 

๋Œ“๊ธ€