์ฝ˜ํ…์ธ  ๋Œ€ํ‘œ ์ด๋ฏธ์ง€ - ๐Ÿ—๏ธ C++ ๋””์ž์ธ ํŒจํ„ด ์™„์ „ ์ •๋ณต

๐Ÿ—๏ธ C++ ๋””์ž์ธ ํŒจํ„ด ์™„์ „ ์ •๋ณต

Gang of Four ํŒจํ„ด ๊ตฌํ˜„๋ถ€ํ„ฐ ์‹ค์ „ ํ™œ์šฉ๊นŒ์ง€, ์ง„์งœ ์“ธ๋ชจ์žˆ๋Š” ๊ฐ€์ด๋“œ

Design Patterns ยท GoF ยท C++ Implementation

๐ŸŽฏ GoF 23๊ฐ€์ง€ ํŒจํ„ด ๐Ÿ’ป C++ ์‹ค์ „ ์ฝ”๋“œ ๐Ÿš€ ํ˜„์—… ํ™œ์šฉ๋ฒ•

์•ผ ์†”์งํžˆ ๋งํ•˜์ž๋ฉด... ๋””์ž์ธ ํŒจํ„ด ์ฒ˜์Œ ๋“ค์—ˆ์„ ๋•Œ "์ด๊ฒŒ ๋ญ” ์†Œ๋ฆฌ์•ผ?" ํ–ˆ๋˜ ์‚ฌ๋žŒ ๋‚˜๋งŒ ์•„๋‹ˆ์ง€? ๐Ÿ˜…
๊ทผ๋ฐ ๋ง‰์ƒ ๊ณต๋ถ€ํ•˜๊ณ  ๋‚˜๋ฉด "์•„ ์ด๊ฑฐ ์—†์ด ์–ด๋–ป๊ฒŒ ์ฝ”๋”ฉํ–ˆ์ง€?" ์‹ถ์–ด์ง€๋Š” ๊ทธ ๋А๋‚Œ... ์˜ค๋Š˜ ๊ทธ ๋А๋‚Œ ์ œ๋Œ€๋กœ ์ „๋‹ฌํ•ด๋ณผ๊ฒŒ.
Gang of Four(GoF)๊ฐ€ 1994๋…„์— ์ •๋ฆฌํ•œ 23๊ฐ€์ง€ ๋””์ž์ธ ํŒจํ„ด, C++๋กœ ์–ด๋–ป๊ฒŒ ๊ตฌํ˜„ํ•˜๊ณ  ์–ด๋””์— ์“ฐ๋Š”์ง€ ์™„์ „ ํŒŒํ—ค์ณ๋ณด์ž๊ณ ! ๐Ÿ”ฅ


GoF ๋””์ž์ธ ํŒจํ„ด 3๋Œ€ ๋ถ„๋ฅ˜ Gang of Four ํŒจํ„ด ์ง€๋„ ๐Ÿ—บ๏ธ ๐Ÿญ ์ƒ์„ฑ ํŒจํ„ด (Creational) ๊ฐ์ฒด ์ƒ์„ฑ ๋ฐฉ์‹์„ ์บก์Аํ™” Singleton ยท Factory Method Abstract Factory ยท Builder Prototype ์ด 5๊ฐ€์ง€ ํŒจํ„ด ์œ ์—ฐํ•˜๊ณ  ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ๊ฐ์ฒด ์ƒ์„ฑ ๋ฉ”์ปค๋‹ˆ์ฆ˜ ์ œ๊ณต ๐Ÿ”ง ๊ตฌ์กฐ ํŒจํ„ด (Structural) ํด๋ž˜์Šค/๊ฐ์ฒด ์กฐํ•ฉ ๋ฐฉ์‹ ์ •์˜ Adapter ยท Bridge ยท Composite Decorator ยท Facade ยท Flyweight Proxy ์ด 7๊ฐ€์ง€ ํŒจํ„ด ํด๋ž˜์Šค์™€ ๊ฐ์ฒด๋ฅผ ๋” ํฐ ๊ตฌ์กฐ๋กœ ์กฐํ•ฉํ•˜๋Š” ๋ฐฉ๋ฒ• ๐ŸŽญ ํ–‰๋™ ํŒจํ„ด (Behavioral) ๊ฐ์ฒด ๊ฐ„ ์ƒํ˜ธ์ž‘์šฉ ๋ฐ ์ฑ…์ž„ ๋ถ„๋ฐฐ Chain of Resp. ยท Command Iterator ยท Mediator ยท Memento Observer ยท State ยท Strategy Template Method ยท Visitor ์ด 11๊ฐ€์ง€ ํŒจํ„ด ์•Œ๊ณ ๋ฆฌ์ฆ˜๊ณผ ๊ฐ์ฒด ๊ฐ„ ์ฑ…์ž„ ํ• ๋‹น GoF (Gang of Four) - Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides ยท 1994
๐Ÿ’ก GoF๊ฐ€ ๋ญ”๋ฐ?
"Gang of Four"๋Š” 1994๋…„ Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides ์ด 4๋ช…์ด ์“ด ์ฑ… "Design Patterns: Elements of Reusable Object-Oriented Software"์—์„œ ์œ ๋ž˜ํ–ˆ์–ด. ์ด ์ฑ…์—์„œ 23๊ฐ€์ง€ ํŒจํ„ด์„ ์ •๋ฆฌํ–ˆ๊ณ , ์ง€๊ธˆ๋„ ์†Œํ”„ํŠธ์›จ์–ด ๊ณตํ•™์˜ ๋ฐ”์ด๋ธ”๋กœ ๋ถˆ๋ฆผ ใ„นใ…‡ ๋ ˆ์ „๋“œ ์ฑ…์ž„ ใ…‹ใ…‹

๐Ÿญ 1๋ถ€: ์ƒ์„ฑ ํŒจํ„ด (Creational Patterns)

์ƒ์„ฑ ํŒจํ„ด์€ ๊ฐ์ฒด๋ฅผ ์–ด๋–ป๊ฒŒ ๋งŒ๋“ค์ง€์— ๋Œ€ํ•œ ๊ณ ๋ฏผ์„ ํ•ด๊ฒฐํ•ด์ค˜.
"๊ทธ๋ƒฅ new ์“ฐ๋ฉด ๋˜๋Š” ๊ฑฐ ์•„๋ƒ?" ๋ผ๊ณ  ์ƒ๊ฐํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ... ๊ทธ๊ฒŒ ๋ฌธ์ œ์˜ ์‹œ์ž‘์ด๊ฑฐ๋“  ใ…‹ใ…‹ใ…‹
๊ฐ์ฒด ์ƒ์„ฑ ๋กœ์ง์ด ์—ฌ๊ธฐ์ €๊ธฐ ํผ์ง€๋ฉด ๋‚˜์ค‘์— ์ˆ˜์ •ํ•  ๋•Œ ์ง€์˜ฅ์„ ๋ง›๋ณด๊ฒŒ ๋จ. ๊ทธ๋ž˜์„œ ์ƒ์„ฑ ํŒจํ„ด์ด ํ•„์š”ํ•œ ๊ฑฐ์•ผ!

๐Ÿ”’ 1-1. Singleton ํŒจํ„ด
์ƒ์„ฑ ํŒจํ„ด ๊ฐ€์žฅ ์œ ๋ช… ๋…ผ๋ž€์˜ ํŒจํ„ด

ํ•ต์‹ฌ ๊ฐœ๋…: ํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค๊ฐ€ ๋”ฑ ํ•˜๋‚˜๋งŒ ์กด์žฌํ•˜๋„๋ก ๋ณด์žฅํ•˜๊ณ , ์ „์—ญ ์ ‘๊ทผ์ ์„ ์ œ๊ณตํ•˜๋Š” ํŒจํ„ด์ด์•ผ.
๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์—ฐ๊ฒฐ, ๋กœ๊ทธ ์‹œ์Šคํ…œ, ์„ค์ • ๊ด€๋ฆฌ์ž ๊ฐ™์€ ๊ณณ์—์„œ ์ž์ฃผ ์”€.

C++์—์„œ Singleton ๊ตฌํ˜„ํ•  ๋•Œ ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋“œ ํ™˜๊ฒฝ ๊ณ ๋ ค ์•ˆ ํ•˜๋ฉด ์ง„์งœ ํฐ์ผ๋‚จ ๐Ÿ˜ฑ
C++11๋ถ€ํ„ฐ๋Š” Meyers' Singleton์ด ๊ฐ€์žฅ ์•ˆ์ „ํ•˜๊ณ  ๊น”๋”ํ•œ ๋ฐฉ๋ฒ•์œผ๋กœ ์ธ์ •๋ฐ›๊ณ  ์žˆ์–ด!


// โœ… Meyers' Singleton - C++11 ์ดํ›„ ๊ฐ€์žฅ ์•ˆ์ „ํ•œ ๋ฐฉ๋ฒ•
#include <iostream>
#include <string>

class Logger {
public:
    // ์ •์  ๋ฉ”์„œ๋“œ๋กœ ์œ ์ผํ•œ ์ธ์Šคํ„ด์Šค ๋ฐ˜ํ™˜
    static Logger& getInstance() {
        static Logger instance; // C++11: ์Šค๋ ˆ๋“œ ์•ˆ์ „ ๋ณด์žฅ!
        return instance;
    }
    
    void log(const std::string& message) {
        std::cout << "[LOG] " << message << std::endl;
    }
    
    // ๋ณต์‚ฌ ์ƒ์„ฑ์ž์™€ ๋Œ€์ž… ์—ฐ์‚ฐ์ž ์‚ญ์ œ (์ธ์Šคํ„ด์Šค ๋ณต์‚ฌ ๋ฐฉ์ง€)
    Logger(const Logger&) = delete;
    Logger& operator=(const Logger&) = delete;

private:
    Logger() { 
        std::cout << "Logger ์ดˆ๊ธฐํ™” ์™„๋ฃŒ!" << std::endl; 
    }
    ~Logger() = default;
};

int main() {
    Logger& logger1 = Logger::getInstance();
    Logger& logger2 = Logger::getInstance();
    
    logger1.log("์ฒซ ๋ฒˆ์งธ ๋กœ๊ทธ ๋ฉ”์‹œ์ง€");
    logger2.log("๋‘ ๋ฒˆ์งธ ๋กœ๊ทธ ๋ฉ”์‹œ์ง€");
    
    // ๊ฐ™์€ ์ธ์Šคํ„ด์Šค์ธ์ง€ ํ™•์ธ
    std::cout << "๊ฐ™์€ ์ธ์Šคํ„ด์Šค? " 
              << (&logger1 == &logger2 ? "YES โœ…" : "NO โŒ") 
              << std::endl;
    return 0;
}
โš ๏ธ Singleton ์ฃผ์˜์‚ฌํ•ญ!
Singleton์€ ์ „์—ญ ์ƒํƒœ๋ฅผ ๋งŒ๋“ค์–ด์„œ ํ…Œ์ŠคํŠธํ•˜๊ธฐ ์–ด๋ ต๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ์–ด. ๋‚จ์šฉํ•˜๋ฉด ์•ˆ ๋˜๊ณ , ์ง„์งœ ํ•„์š”ํ•œ ๊ฒฝ์šฐ์—๋งŒ ์จ์•ผ ํ•ด. ํ˜„์—…์—์„œ๋Š” "Singleton์€ ์•ˆํ‹ฐํŒจํ„ด์ด๋‹ค"๋ผ๋Š” ๋ง๋„ ์žˆ์„ ์ •๋„๋‹ˆ๊นŒ ใ…‹ใ…‹ ์ƒํ™ฉ ๋ด๊ฐ€๋ฉด์„œ ์จ์•ผ ํ•จ!
๐Ÿญ 1-2. Factory Method ํŒจํ„ด
์ƒ์„ฑ ํŒจํ„ด OCP ์›์น™ ํ™•์žฅ์„ฑ ๊ตฟ

ํ•ต์‹ฌ ๊ฐœ๋…: ๊ฐ์ฒด ์ƒ์„ฑ์„ ์„œ๋ธŒํด๋ž˜์Šค์— ์œ„์ž„ํ•˜๋Š” ํŒจํ„ด. ์–ด๋–ค ํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ๋งŒ๋“ค์ง€๋ฅผ ์„œ๋ธŒํด๋ž˜์Šค๊ฐ€ ๊ฒฐ์ •ํ•˜๊ฒŒ ํ•ด์ค˜.
"Open/Closed Principle" - ํ™•์žฅ์—๋Š” ์—ด๋ ค์žˆ๊ณ , ์ˆ˜์ •์—๋Š” ๋‹ซํ˜€์žˆ๋Š” ์„ค๊ณ„๋ฅผ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•จ!


// ๐Ÿญ Factory Method ํŒจํ„ด ์˜ˆ์ œ - ๊ฒŒ์ž„ ์บ๋ฆญํ„ฐ ์ƒ์„ฑ
#include <iostream>
#include <memory>
#include <string>

// ์ถ”์ƒ ์ œํ’ˆ (Product)
class Character {
public:
    virtual ~Character() = default;
    virtual void attack() = 0;
    virtual std::string getName() const = 0;
};

// ๊ตฌ์ฒด ์ œํ’ˆ๋“ค (Concrete Products)
class Warrior : public Character {
public:
    void attack() override {
        std::cout << getName() << ": ๊ฒ€์œผ๋กœ ๊ฐ•ํƒ€! โš”๏ธ" << std::endl;
    }
    std::string getName() const override { return "์ „์‚ฌ"; }
};

class Mage : public Character {
public:
    void attack() override {
        std::cout << getName() << ": ํŒŒ์ด์–ด๋ณผ ๋ฐœ์‚ฌ! ๐Ÿ”ฅ" << std::endl;
    }
    std::string getName() const override { return "๋งˆ๋ฒ•์‚ฌ"; }
};

class Archer : public Character {
public:
    void attack() override {
        std::cout << getName() << ": ํ™”์‚ด ๋ฐœ์‚ฌ! ๐Ÿน" << std::endl;
    }
    std::string getName() const override { return "๊ถ์ˆ˜"; }
};

// ์ถ”์ƒ ์ƒ์„ฑ์ž (Creator)
class CharacterFactory {
public:
    virtual ~CharacterFactory() = default;
    // Factory Method - ์„œ๋ธŒํด๋ž˜์Šค์—์„œ ๊ตฌํ˜„
    virtual std::unique_ptr<Character> createCharacter() = 0;
    
    // ํ…œํ”Œ๋ฆฟ ๋ฉ”์„œ๋“œ - ์ƒ์„ฑ ํ›„ ๊ณตํ†ต ์ฒ˜๋ฆฌ
    void spawnCharacter() {
        auto character = createCharacter();
        std::cout << character->getName() << " ์บ๋ฆญํ„ฐ ์†Œํ™˜ ์™„๋ฃŒ! ๐ŸŽฎ" << std::endl;
        character->attack();
    }
};

// ๊ตฌ์ฒด ์ƒ์„ฑ์ž๋“ค (Concrete Creators)
class WarriorFactory : public CharacterFactory {
public:
    std::unique_ptr<Character> createCharacter() override {
        return std::make_unique<Warrior>();
    }
};

class MageFactory : public CharacterFactory {
public:
    std::unique_ptr<Character> createCharacter() override {
        return std::make_unique<Mage>();
    }
};

int main() {
    WarriorFactory warriorFactory;
    MageFactory mageFactory;
    
    warriorFactory.spawnCharacter();
    mageFactory.spawnCharacter();
    
    return 0;
}
๐Ÿ—๏ธ 1-3. Abstract Factory ํŒจํ„ด
์ƒ์„ฑ ํŒจํ„ด ์ œํ’ˆ๊ตฐ ์ƒ์„ฑ ํ”Œ๋žซํผ ๋…๋ฆฝ์„ฑ

ํ•ต์‹ฌ ๊ฐœ๋…: ๊ด€๋ จ๋œ ๊ฐ์ฒด๋“ค์˜ ํŒจ๋ฐ€๋ฆฌ(์ œํ’ˆ๊ตฐ)๋ฅผ ์ƒ์„ฑํ•˜๋Š” ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ œ๊ณตํ•ด. Factory Method์˜ ์ƒ์œ„ ๋ฒ„์ „์ด๋ผ๊ณ  ๋ณด๋ฉด ๋ผ.
UI ์ปดํฌ๋„ŒํŠธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ, ํฌ๋กœ์Šค ํ”Œ๋žซํผ ๊ฐœ๋ฐœ์—์„œ ์ž์ฃผ ๋“ฑ์žฅํ•จ!


// ๐ŸŽจ Abstract Factory - UI ํ…Œ๋งˆ ์‹œ์Šคํ…œ
#include <iostream>
#include <memory>
#include <string>

// ์ถ”์ƒ ์ œํ’ˆ๋“ค
class Button {
public:
    virtual ~Button() = default;
    virtual void render() = 0;
};

class TextBox {
public:
    virtual ~TextBox() = default;
    virtual void render() = 0;
};

// ๋‹คํฌ ํ…Œ๋งˆ ์ œํ’ˆ๋“ค
class DarkButton : public Button {
public:
    void render() override {
        std::cout << "๐ŸŒ‘ [๋‹คํฌ ๋ฒ„ํŠผ] ์–ด๋‘์šด ๋ฐฐ๊ฒฝ์— ํฐ ํ…์ŠคํŠธ" << std::endl;
    }
};

class DarkTextBox : public TextBox {
public:
    void render() override {
        std::cout << "๐ŸŒ‘ [๋‹คํฌ ํ…์ŠคํŠธ๋ฐ•์Šค] ์–ด๋‘์šด ์ž…๋ ฅ์ฐฝ" << std::endl;
    }
};

// ๋ผ์ดํŠธ ํ…Œ๋งˆ ์ œํ’ˆ๋“ค
class LightButton : public Button {
public:
    void render() override {
        std::cout << "โ˜€๏ธ [๋ผ์ดํŠธ ๋ฒ„ํŠผ] ๋ฐ์€ ๋ฐฐ๊ฒฝ์— ๊ฒ€์€ ํ…์ŠคํŠธ" << std::endl;
    }
};

class LightTextBox : public TextBox {
public:
    void render() override {
        std::cout << "โ˜€๏ธ [๋ผ์ดํŠธ ํ…์ŠคํŠธ๋ฐ•์Šค] ๋ฐ์€ ์ž…๋ ฅ์ฐฝ" << std::endl;
    }
};

// ์ถ”์ƒ ํŒฉํ† ๋ฆฌ
class UIFactory {
public:
    virtual ~UIFactory() = default;
    virtual std::unique_ptr<Button> createButton() = 0;
    virtual std::unique_ptr<TextBox> createTextBox() = 0;
};

// ๊ตฌ์ฒด ํŒฉํ† ๋ฆฌ๋“ค
class DarkThemeFactory : public UIFactory {
public:
    std::unique_ptr<Button> createButton() override {
        return std::make_unique<DarkButton>();
    }
    std::unique_ptr<TextBox> createTextBox() override {
        return std::make_unique<DarkTextBox>();
    }
};

class LightThemeFactory : public UIFactory {
public:
    std::unique_ptr<Button> createButton() override {
        return std::make_unique<LightButton>();
    }
    std::unique_ptr<TextBox> createTextBox() override {
        return std::make_unique<LightTextBox>();
    }
};

// ํด๋ผ์ด์–ธํŠธ ์ฝ”๋“œ
void renderUI(UIFactory& factory) {
    auto button = factory.createButton();
    auto textBox = factory.createTextBox();
    button->render();
    textBox->render();
}

int main() {
    std::cout << "=== ๋‹คํฌ ํ…Œ๋งˆ ===" << std::endl;
    DarkThemeFactory darkFactory;
    renderUI(darkFactory);
    
    std::cout << "\n=== ๋ผ์ดํŠธ ํ…Œ๋งˆ ===" << std::endl;
    LightThemeFactory lightFactory;
    renderUI(lightFactory);
    
    return 0;
}
๐Ÿ”จ 1-4. Builder ํŒจํ„ด
์ƒ์„ฑ ํŒจํ„ด ๋ณต์žกํ•œ ๊ฐ์ฒด ๋‹จ๊ณ„๋ณ„ ์ƒ์„ฑ

ํ•ต์‹ฌ ๊ฐœ๋…: ๋ณต์žกํ•œ ๊ฐ์ฒด๋ฅผ ๋‹จ๊ณ„๋ณ„๋กœ ์ƒ์„ฑํ•˜๋Š” ํŒจํ„ด. ์ƒ์„ฑ์ž์— ๋งค๊ฐœ๋ณ€์ˆ˜๊ฐ€ ๋„ˆ๋ฌด ๋งŽ์•„์งˆ ๋•Œ ๊ตฌ์›์ž ์—ญํ• ์„ ํ•ด์คŒ!
"Telescoping Constructor" ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๋ฐ ์ตœ๊ณ ์•ผ. ํ˜„๋Œ€ C++์—์„œ๋Š” Fluent Interface ์Šคํƒ€์ผ๋กœ ๋งŽ์ด ์”€.


// ๐Ÿ” Builder ํŒจํ„ด - ๋ฒ„๊ฑฐ ์ฃผ๋ฌธ ์‹œ์Šคํ…œ (Fluent Interface)
#include <iostream>
#include <string>
#include <vector>

class Burger {
public:
    std::string bun;           // ๋ฒˆ ์ข…๋ฅ˜
    std::string patty;         // ํŒจํ‹ฐ ์ข…๋ฅ˜
    bool cheese = false;       // ์น˜์ฆˆ ์—ฌ๋ถ€
    bool lettuce = false;      // ์–‘์ƒ์ถ” ์—ฌ๋ถ€
    bool tomato = false;       // ํ† ๋งˆํ†  ์—ฌ๋ถ€
    std::string sauce;         // ์†Œ์Šค
    int pattyCount = 1;        // ํŒจํ‹ฐ ๊ฐœ์ˆ˜
    
    void display() const {
        std::cout << "\n๐Ÿ” === ์ฃผ๋ฌธํ•˜์‹  ๋ฒ„๊ฑฐ ===" << std::endl;
        std::cout << "๋ฒˆ: " << bun << std::endl;
        std::cout << "ํŒจํ‹ฐ: " << patty << " x" << pattyCount << std::endl;
        std::cout << "์น˜์ฆˆ: " << (cheese ? "โœ…" : "โŒ") << std::endl;
        std::cout << "์–‘์ƒ์ถ”: " << (lettuce ? "โœ…" : "โŒ") << std::endl;
        std::cout << "ํ† ๋งˆํ† : " << (tomato ? "โœ…" : "โŒ") << std::endl;
        std::cout << "์†Œ์Šค: " << sauce << std::endl;
        std::cout << "=====================" << std::endl;
    }
};

class BurgerBuilder {
private:
    Burger burger;
    
public:
    BurgerBuilder& setBun(const std::string& bun) {
        burger.bun = bun;
        return *this; // ๋ฉ”์„œ๋“œ ์ฒด์ด๋‹์„ ์œ„ํ•ด ์ž๊ธฐ ์ž์‹  ๋ฐ˜ํ™˜
    }
    
    BurgerBuilder& setPatty(const std::string& patty, int count = 1) {
        burger.patty = patty;
        burger.pattyCount = count;
        return *this;
    }
    
    BurgerBuilder& addCheese() {
        burger.cheese = true;
        return *this;
    }
    
    BurgerBuilder& addLettuce() {
        burger.lettuce = true;
        return *this;
    }
    
    BurgerBuilder& addTomato() {
        burger.tomato = true;
        return *this;
    }
    
    BurgerBuilder& setSauce(const std::string& sauce) {
        burger.sauce = sauce;
        return *this;
    }
    
    Burger build() {
        return burger; // ์ตœ์ข… ๊ฐ์ฒด ๋ฐ˜ํ™˜
    }
};

int main() {
    // Fluent Interface๋กœ ๋ฒ„๊ฑฐ ์ฃผ๋ฌธ - ์ฝ๊ธฐ ์‰ฝ๊ณ  ์ง๊ด€์ !
    Burger myBurger = BurgerBuilder()
        .setBun("ํ†ต๋ฐ€ ๋ฒˆ")
        .setPatty("์†Œ๊ณ ๊ธฐ", 2)
        .addCheese()
        .addLettuce()
        .addTomato()
        .setSauce("ํŠน์ œ ์†Œ์Šค")
        .build();
    
    myBurger.display();
    
    // ๊ฐ„๋‹จํ•œ ๋ฒ„๊ฑฐ๋„ ์‰ฝ๊ฒŒ!
    Burger simpleBurger = BurgerBuilder()
        .setBun("์ผ๋ฐ˜ ๋ฒˆ")
        .setPatty("๋‹ญ๊ณ ๊ธฐ")
        .setSauce("๋งˆ์š”๋„ค์ฆˆ")
        .build();
    
    simpleBurger.display();
    
    return 0;
}
๐Ÿ’ก Builder ํŒจํ„ด ๊ฟ€ํŒ!
C++์—์„œ Builder ํŒจํ„ด์„ ์“ธ ๋•Œ return *this;๋กœ ๋ฉ”์„œ๋“œ ์ฒด์ด๋‹์„ ๊ตฌํ˜„ํ•˜๋ฉด ์ฝ”๋“œ๊ฐ€ ํ›จ์”ฌ ์ฝ๊ธฐ ์ข‹์•„์ ธ. ์ด๊ฑธ "Fluent Interface"๋ผ๊ณ  ํ•˜๋Š”๋ฐ, ์žฌ๋Šฅ๋„ท ๊ฐ™์€ ํ”Œ๋žซํผ์—์„œ ๊ฐœ๋ฐœ ๊ด€๋ จ ์žฌ๋Šฅ์„ ๊ณต์œ ํ•  ๋•Œ๋„ ์ด๋Ÿฐ ํŒจํ„ด ์„ค๋ช…์ด ์ธ๊ธฐ ์žˆ๋”๋ผ๊ณ ! ๐Ÿ˜„
๐Ÿงฌ 1-5. Prototype ํŒจํ„ด
์ƒ์„ฑ ํŒจํ„ด ๋ณต์‚ฌ ๊ธฐ๋ฐ˜ ์„ฑ๋Šฅ ์ตœ์ ํ™”

ํ•ต์‹ฌ ๊ฐœ๋…: ๊ธฐ์กด ๊ฐ์ฒด๋ฅผ ๋ณต์‚ฌ(clone)ํ•ด์„œ ์ƒˆ ๊ฐ์ฒด๋ฅผ ๋งŒ๋“œ๋Š” ํŒจํ„ด. ๊ฐ์ฒด ์ƒ์„ฑ ๋น„์šฉ์ด ํด ๋•Œ ์œ ์šฉํ•ด!
C++์—์„œ๋Š” ๋ณต์‚ฌ ์ƒ์„ฑ์ž์™€ clone() ๋ฉ”์„œ๋“œ๋ฅผ ํ™œ์šฉํ•ด์„œ ๊ตฌํ˜„ํ•จ.


// ๐Ÿงฌ Prototype ํŒจํ„ด - ๊ฒŒ์ž„ ๋ชฌ์Šคํ„ฐ ๋ณต์ œ
#include <iostream>
#include <memory>
#include <string>

class Monster {
public:
    virtual ~Monster() = default;
    virtual std::unique_ptr<Monster> clone() const = 0; // ํ•ต์‹ฌ!
    virtual void display() const = 0;
    
    std::string name;
    int hp;
    int attack;
};

class Goblin : public Monster {
public:
    Goblin(const std::string& n, int h, int a) {
        name = n; hp = h; attack = a;
    }
    
    // ๋ณต์‚ฌ ์ƒ์„ฑ์ž ๊ธฐ๋ฐ˜ clone
    std::unique_ptr<Monster> clone() const override {
        return std::make_unique<Goblin>(*this);
    }
    
    void display() const override {
        std::cout << "๐Ÿ‘บ " << name << " | HP:" << hp << " | ATK:" << attack << std::endl;
    }
};

class Dragon : public Monster {
public:
    Dragon(const std::string& n, int h, int a) {
        name = n; hp = h; attack = a;
    }
    
    std::unique_ptr<Monster> clone() const override {
        return std::make_unique<Dragon>(*this);
    }
    
    void display() const override {
        std::cout << "๐Ÿ‰ " << name << " | HP:" << hp << " | ATK:" << attack << std::endl;
    }
};

int main() {
    // ์›๋ณธ ๋ชฌ์Šคํ„ฐ ์ƒ์„ฑ (๋น„์šฉ์ด ํฐ ์ž‘์—…์ด๋ผ๊ณ  ๊ฐ€์ •)
    auto originalGoblin = std::make_unique<Goblin>("๊ณ ๋ธ”๋ฆฐ ์™•", 100, 25);
    
    // ๋ณต์ œ๋กœ ๋น ๋ฅด๊ฒŒ ์—ฌ๋Ÿฌ ๋ชฌ์Šคํ„ฐ ์ƒ์„ฑ!
    auto goblin1 = originalGoblin->clone();
    auto goblin2 = originalGoblin->clone();
    
    // ๋ณต์ œ๋œ ๋ชฌ์Šคํ„ฐ ์ปค์Šคํ„ฐ๋งˆ์ด์ง•
    goblin1->name = "๊ณ ๋ธ”๋ฆฐ ๋ณ‘์‚ฌ A";
    goblin1->hp = 50;
    goblin2->name = "๊ณ ๋ธ”๋ฆฐ ๋ณ‘์‚ฌ B";
    goblin2->hp = 60;
    
    std::cout << "=== ๋ชฌ์Šคํ„ฐ ๋ชฉ๋ก ===" << std::endl;
    originalGoblin->display();
    goblin1->display();
    goblin2->display();
    
    return 0;
}

๐Ÿ”ง 2๋ถ€: ๊ตฌ์กฐ ํŒจํ„ด (Structural Patterns)

๊ตฌ์กฐ ํŒจํ„ด์€ ํด๋ž˜์Šค์™€ ๊ฐ์ฒด๋ฅผ ์–ด๋–ป๊ฒŒ ์กฐํ•ฉํ• ์ง€์— ๋Œ€ํ•œ ํ•ด๋‹ต์„ ์ค˜.
๋ ˆ๊ณ  ๋ธ”๋ก์ฒ˜๋Ÿผ ์—ฌ๋Ÿฌ ํด๋ž˜์Šค๋ฅผ ์กฐํ•ฉํ•ด์„œ ๋” ํฐ ๊ตฌ์กฐ๋ฅผ ๋งŒ๋“œ๋Š” ๋ฐฉ๋ฒ•์ด๋ผ๊ณ  ์ƒ๊ฐํ•˜๋ฉด ๋จ! ๐Ÿงฑ

๐Ÿ”ง ๊ตฌ์กฐ ํŒจํ„ด ํ•œ๋ˆˆ์— ๋ณด๊ธฐ Adapter ํ˜ธํ™˜๋˜์ง€ ์•Š๋Š” ์ธํ„ฐํŽ˜์ด์Šค ์—ฐ๊ฒฐ ๐Ÿ”Œ Bridge ์ถ”์ƒํ™”์™€ ๊ตฌํ˜„ ๋ถ„๋ฆฌ ๐ŸŒ‰ Composite ํŠธ๋ฆฌ ๊ตฌ์กฐ๋กœ ๊ฐ์ฒด ๊ตฌ์„ฑ ๐ŸŒณ Decorator ๋™์ ์œผ๋กœ ๊ธฐ๋Šฅ ์ถ”๊ฐ€ ๐ŸŽ€ Facade ๋ณต์žกํ•œ ์‹œ์Šคํ…œ ๋‹จ์ˆœ ์ธํ„ฐํŽ˜์ด์Šค ๐Ÿ  Flyweight ๊ณต์œ ๋กœ ๋ฉ”๋ชจ๋ฆฌ ์ ˆ์•ฝ ๐Ÿชถ Proxy ๋Œ€๋ฆฌ์ž๋กœ ์ ‘๊ทผ ์ œ์–ด ๐Ÿ›ก๏ธ ๊ตฌ์กฐ ํŒจํ„ด์€ ํด๋ž˜์Šค/๊ฐ์ฒด๋ฅผ ์กฐํ•ฉํ•ด ๋” ํฐ ๊ตฌ์กฐ๋ฅผ ๋งŒ๋“œ๋Š” ๋ฐฉ๋ฒ•์„ ๋‹ค๋ค„ ๐ŸŽฏ ์‹ค์ œ ์‚ฌ์šฉ ์‚ฌ๋ก€ โ€ข Adapter: ๊ตฌํ˜• API๋ฅผ ์‹ ํ˜• ์‹œ์Šคํ…œ์— ์—ฐ๊ฒฐํ•  ๋•Œ โ€ข Decorator: ์ŠคํŠธ๋ฆผ์— ๊ธฐ๋Šฅ ์ถ”๊ฐ€ (์•”ํ˜ธํ™”, ์••์ถ• ๋“ฑ) โ€ข Facade: ๋ณต์žกํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๋‹จ์ˆœํ•˜๊ฒŒ ๊ฐ์Œ€ ๋•Œ โ€ข Proxy: ์ง€์—ฐ ๋กœ๋”ฉ, ์บ์‹ฑ, ์ ‘๊ทผ ์ œ์–ด ๊ตฌํ˜„ ์‹œ ๐Ÿ’ก ์„ ํƒ ๊ธฐ์ค€ โ€ข ์ธํ„ฐํŽ˜์ด์Šค ๋ถˆ์ผ์น˜ โ†’ Adapter โ€ข ๊ธฐ๋Šฅ ๋™์  ์ถ”๊ฐ€ โ†’ Decorator โ€ข ๋ฉ”๋ชจ๋ฆฌ ์ ˆ์•ฝ ํ•„์š” โ†’ Flyweight โ€ข ์ ‘๊ทผ ์ œ์–ด ํ•„์š” โ†’ Proxy
๐Ÿ”Œ 2-1. Adapter ํŒจํ„ด
๊ตฌ์กฐ ํŒจํ„ด ์ธํ„ฐํŽ˜์ด์Šค ๋ณ€ํ™˜ ๋ ˆ๊ฑฐ์‹œ ์ฝ”๋“œ

ํ•ต์‹ฌ ๊ฐœ๋…: ํ˜ธํ™˜๋˜์ง€ ์•Š๋Š” ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ฐ€์ง„ ํด๋ž˜์Šค๋“ค์ด ํ•จ๊ป˜ ๋™์ž‘ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ด์ฃผ๋Š” ํŒจํ„ด.
110V ์ฝ˜์„ผํŠธ์— 220V ํ”Œ๋Ÿฌ๊ทธ ๊ฝ‚์„ ๋•Œ ์–ด๋Œ‘ํ„ฐ ์“ฐ๋Š” ๊ฑฐ๋ž‘ ๋˜‘๊ฐ™์€ ๊ฐœ๋…์ž„ ใ…‹ใ…‹


// ๐Ÿ”Œ Adapter ํŒจํ„ด - ๊ตฌํ˜• ๊ฒฐ์ œ ์‹œ์Šคํ…œ ์—ฐ๋™
#include <iostream>
#include <string>

// ์ƒˆ ์‹œ์Šคํ…œ์ด ๊ธฐ๋Œ€ํ•˜๋Š” ์ธํ„ฐํŽ˜์ด์Šค (Target)
class PaymentProcessor {
public:
    virtual ~PaymentProcessor() = default;
    virtual void processPayment(const std::string& amount) = 0;
};

// ๊ตฌํ˜• ๊ฒฐ์ œ ์‹œ์Šคํ…œ (Adaptee) - ๋ณ€๊ฒฝ ๋ถˆ๊ฐ€๋Šฅํ•œ ๋ ˆ๊ฑฐ์‹œ ์ฝ”๋“œ
class LegacyPaymentSystem {
public:
    void makePayment(double amount, const std::string& currency) {
        std::cout << "๐Ÿ’ณ ๊ตฌํ˜• ์‹œ์Šคํ…œ์œผ๋กœ ๊ฒฐ์ œ: " 
                  << amount << " " << currency << std::endl;
    }
};

// ์–ด๋Œ‘ํ„ฐ - ๊ตฌํ˜• ์‹œ์Šคํ…œ์„ ์ƒˆ ์ธํ„ฐํŽ˜์ด์Šค๋กœ ๊ฐ์Œˆ
class PaymentAdapter : public PaymentProcessor {
private:
    LegacyPaymentSystem legacySystem;
    
public:
    void processPayment(const std::string& amount) override {
        // ๋ฌธ์ž์—ด ๊ธˆ์•ก์„ ๊ตฌํ˜• ์‹œ์Šคํ…œ ํ˜•์‹์œผ๋กœ ๋ณ€ํ™˜
        double numericAmount = std::stod(amount);
        legacySystem.makePayment(numericAmount, "KRW");
        std::cout << "โœ… ์–ด๋Œ‘ํ„ฐ๋ฅผ ํ†ตํ•ด ๊ฒฐ์ œ ์™„๋ฃŒ!" << std::endl;
    }
};

// ํด๋ผ์ด์–ธํŠธ ์ฝ”๋“œ - ์ƒˆ ์ธํ„ฐํŽ˜์ด์Šค๋งŒ ์•Œ๋ฉด ๋จ
void checkout(PaymentProcessor& processor, const std::string& amount) {
    std::cout << "๊ฒฐ์ œ ์ฒ˜๋ฆฌ ์ค‘..." << std::endl;
    processor.processPayment(amount);
}

int main() {
    PaymentAdapter adapter;
    checkout(adapter, "50000");
    return 0;
}
๐ŸŽ€ 2-2. Decorator ํŒจํ„ด
๊ตฌ์กฐ ํŒจํ„ด ๋™์  ๊ธฐ๋Šฅ ์ถ”๊ฐ€ ์ƒ์† ๋Œ€์•ˆ

ํ•ต์‹ฌ ๊ฐœ๋…: ๊ฐ์ฒด์— ๋™์ ์œผ๋กœ ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•˜๋Š” ํŒจํ„ด. ์ƒ์†๋ณด๋‹ค ์œ ์—ฐํ•œ ๊ธฐ๋Šฅ ํ™•์žฅ ๋ฐฉ๋ฒ•!
C++ STL์˜ ์ŠคํŠธ๋ฆผ ์‹œ์Šคํ…œ์ด ์ด ํŒจํ„ด์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์–ด. ifstream์— ๋ฒ„ํผ๋ง, ์•”ํ˜ธํ™” ๋“ฑ์„ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ!


// โ˜• Decorator ํŒจํ„ด - ์ปคํ”ผ ์ฃผ๋ฌธ ์‹œ์Šคํ…œ
#include <iostream>
#include <memory>
#include <string>

// ๊ธฐ๋ณธ ์ปดํฌ๋„ŒํŠธ ์ธํ„ฐํŽ˜์ด์Šค
class Coffee {
public:
    virtual ~Coffee() = default;
    virtual std::string getDescription() const = 0;
    virtual double getCost() const = 0;
};

// ๊ธฐ๋ณธ ์ปคํ”ผ (Concrete Component)
class Espresso : public Coffee {
public:
    std::string getDescription() const override {
        return "์—์Šคํ”„๋ ˆ์†Œ";
    }
    double getCost() const override { return 2000.0; }
};

class Americano : public Coffee {
public:
    std::string getDescription() const override {
        return "์•„๋ฉ”๋ฆฌ์นด๋…ธ";
    }
    double getCost() const override { return 3000.0; }
};

// ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ๊ธฐ๋ณธ ํด๋ž˜์Šค
class CoffeeDecorator : public Coffee {
protected:
    std::unique_ptr<Coffee> coffee;
    
public:
    CoffeeDecorator(std::unique_ptr<Coffee> c) : coffee(std::move(c)) {}
};

// ๊ตฌ์ฒด ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋“ค
class MilkDecorator : public CoffeeDecorator {
public:
    MilkDecorator(std::unique_ptr<Coffee> c) 
        : CoffeeDecorator(std::move(c)) {}
    
    std::string getDescription() const override {
        return coffee->getDescription() + " + ์šฐ์œ ๐Ÿฅ›";
    }
    double getCost() const override {
        return coffee->getCost() + 500.0;
    }
};

class SyrupDecorator : public CoffeeDecorator {
private:
    std::string syrupType;
public:
    SyrupDecorator(std::unique_ptr<Coffee> c, const std::string& syrup) 
        : CoffeeDecorator(std::move(c)), syrupType(syrup) {}
    
    std::string getDescription() const override {
        return coffee->getDescription() + " + " + syrupType + "์‹œ๋Ÿฝ๐Ÿฏ";
    }
    double getCost() const override {
        return coffee->getCost() + 700.0;
    }
};

class WhipDecorator : public CoffeeDecorator {
public:
    WhipDecorator(std::unique_ptr<Coffee> c) 
        : CoffeeDecorator(std::move(c)) {}
    
    std::string getDescription() const override {
        return coffee->getDescription() + " + ํœ˜ํ•‘ํฌ๋ฆผ๐Ÿฆ";
    }
    double getCost() const override {
        return coffee->getCost() + 800.0;
    }
};

int main() {
    // ์•„๋ฉ”๋ฆฌ์นด๋…ธ + ์šฐ์œ  + ๋ฐ”๋‹๋ผ์‹œ๋Ÿฝ + ํœ˜ํ•‘ํฌ๋ฆผ
    std::unique_ptr<Coffee> myOrder = std::make_unique<Americano>();
    myOrder = std::make_unique<MilkDecorator>(std::move(myOrder));
    myOrder = std::make_unique<SyrupDecorator>(std::move(myOrder), "๋ฐ”๋‹๋ผ");
    myOrder = std::make_unique<WhipDecorator>(std::move(myOrder));
    
    std::cout << "โ˜• ์ฃผ๋ฌธ: " << myOrder->getDescription() << std::endl;
    std::cout << "๐Ÿ’ฐ ๊ฐ€๊ฒฉ: " << myOrder->getCost() << "์›" << std::endl;
    
    return 0;
}
๐Ÿ  2-3. Facade ํŒจํ„ด
๊ตฌ์กฐ ํŒจํ„ด ๋ณต์žก์„ฑ ์ˆจ๊ธฐ๊ธฐ ๋‹จ์ˆœํ™”

ํ•ต์‹ฌ ๊ฐœ๋…: ๋ณต์žกํ•œ ์„œ๋ธŒ์‹œ์Šคํ…œ์— ๋Œ€ํ•œ ๋‹จ์ˆœํ™”๋œ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ œ๊ณตํ•˜๋Š” ํŒจํ„ด.
"์Šค๋งˆํŠธํ™ˆ ์•ฑ ํ•˜๋‚˜๋กœ ์กฐ๋ช…, ์—์–ด์ปจ, TV ๋‹ค ์ œ์–ดํ•˜๋Š” ๊ฒƒ"๊ณผ ๊ฐ™์€ ๊ฐœ๋…์ด์•ผ!


// ๐Ÿ  Facade ํŒจํ„ด - ํ™ˆ์‹œ์–ดํ„ฐ ์‹œ์Šคํ…œ
#include <iostream>

// ๋ณต์žกํ•œ ์„œ๋ธŒ์‹œ์Šคํ…œ๋“ค
class Projector {
public:
    void on() { std::cout << "๐Ÿ“ฝ๏ธ ํ”„๋กœ์ ํ„ฐ ์ผœ์ง" << std::endl; }
    void setInput(const std::string& input) { 
        std::cout << "๐Ÿ“ฝ๏ธ ์ž…๋ ฅ: " << input << std::endl; 
    }
    void off() { std::cout << "๐Ÿ“ฝ๏ธ ํ”„๋กœ์ ํ„ฐ ๊บผ์ง" << std::endl; }
};

class SoundSystem {
public:
    void on() { std::cout << "๐Ÿ”Š ์‚ฌ์šด๋“œ ์‹œ์Šคํ…œ ์ผœ์ง" << std::endl; }
    void setVolume(int vol) { 
        std::cout << "๐Ÿ”Š ๋ณผ๋ฅจ: " << vol << std::endl; 
    }
    void setSurroundMode() { 
        std::cout << "๐Ÿ”Š ์„œ๋ผ์šด๋“œ ๋ชจ๋“œ ํ™œ์„ฑํ™”" << std::endl; 
    }
    void off() { std::cout << "๐Ÿ”Š ์‚ฌ์šด๋“œ ์‹œ์Šคํ…œ ๊บผ์ง" << std::endl; }
};

class Lights {
public:
    void dim(int level) { 
        std::cout << "๐Ÿ’ก ์กฐ๋ช… " << level << "% ๋ฐ๊ธฐ" << std::endl; 
    }
    void on() { std::cout << "๐Ÿ’ก ์กฐ๋ช… ์ผœ์ง" << std::endl; }
};

class StreamingService {
public:
    void connect() { std::cout << "๐ŸŒ ์ŠคํŠธ๋ฆฌ๋ฐ ์„œ๋น„์Šค ์—ฐ๊ฒฐ" << std::endl; }
    void play(const std::string& movie) { 
        std::cout << "โ–ถ๏ธ ์žฌ์ƒ: " << movie << std::endl; 
    }
    void stop() { std::cout << "โน๏ธ ์žฌ์ƒ ์ค‘์ง€" << std::endl; }
};

// Facade - ๋ณต์žกํ•œ ์„œ๋ธŒ์‹œ์Šคํ…œ์„ ๋‹จ์ˆœํ•˜๊ฒŒ!
class HomeTheaterFacade {
private:
    Projector projector;
    SoundSystem sound;
    Lights lights;
    StreamingService streaming;
    
public:
    // ์˜ํ™” ๋ณด๊ธฐ - ๋ณต์žกํ•œ ๊ณผ์ •์„ ํ•˜๋‚˜์˜ ๋ฉ”์„œ๋“œ๋กœ!
    void watchMovie(const std::string& movie) {
        std::cout << "\n๐ŸŽฌ === ์˜ํ™” ๋ชจ๋“œ ์‹œ์ž‘ ===" << std::endl;
        lights.dim(20);
        projector.on();
        projector.setInput("HDMI");
        sound.on();
        sound.setSurroundMode();
        sound.setVolume(70);
        streaming.connect();
        streaming.play(movie);
        std::cout << "๐Ÿฟ ์ฆ๊ฑฐ์šด ์˜ํ™” ๊ฐ์ƒ!" << std::endl;
    }
    
    // ์˜ํ™” ์ข…๋ฃŒ
    void endMovie() {
        std::cout << "\n๐ŸŒ™ === ์˜ํ™” ๋ชจ๋“œ ์ข…๋ฃŒ ===" << std::endl;
        streaming.stop();
        sound.off();
        projector.off();
        lights.on();
    }
};

int main() {
    HomeTheaterFacade theater;
    theater.watchMovie("์ธํ„ฐ์Šคํ…”๋ผ");
    // ... ์˜ํ™” ๊ฐ์ƒ ...
    theater.endMovie();
    return 0;
}
๐Ÿ›ก๏ธ 2-4. Proxy ํŒจํ„ด
๊ตฌ์กฐ ํŒจํ„ด ์ ‘๊ทผ ์ œ์–ด ์ง€์—ฐ ๋กœ๋”ฉ

ํ•ต์‹ฌ ๊ฐœ๋…: ๋‹ค๋ฅธ ๊ฐ์ฒด์— ๋Œ€ํ•œ ๋Œ€๋ฆฌ์ž(Proxy)๋ฅผ ์ œ๊ณตํ•˜์—ฌ ์ ‘๊ทผ์„ ์ œ์–ดํ•˜๋Š” ํŒจํ„ด.
Virtual Proxy(์ง€์—ฐ ๋กœ๋”ฉ), Protection Proxy(์ ‘๊ทผ ์ œ์–ด), Remote Proxy(์›๊ฒฉ ๊ฐ์ฒด) ๋“ฑ ๋‹ค์–‘ํ•œ ๋ณ€ํ˜•์ด ์žˆ์–ด!


// ๐Ÿ›ก๏ธ Proxy ํŒจํ„ด - ์ด๋ฏธ์ง€ ์ง€์—ฐ ๋กœ๋”ฉ (Virtual Proxy)
#include <iostream>
#include <string>
#include <memory>

// ๊ณตํ†ต ์ธํ„ฐํŽ˜์ด์Šค
class Image {
public:
    virtual ~Image() = default;
    virtual void display() = 0;
    virtual std::string getFilename() const = 0;
};

// ์‹ค์ œ ๊ฐ์ฒด - ์ƒ์„ฑ ๋น„์šฉ์ด ํผ
class RealImage : public Image {
private:
    std::string filename;
    
    void loadFromDisk() {
        std::cout << "๐Ÿ’พ ๋””์Šคํฌ์—์„œ ๋กœ๋”ฉ: " << filename 
                  << " (์‹œ๊ฐ„ ์†Œ์š”...)" << std::endl;
    }
    
public:
    RealImage(const std::string& file) : filename(file) {
        loadFromDisk(); // ์ƒ์„ฑ ์‹œ ๋ฐ”๋กœ ๋กœ๋”ฉ
    }
    
    void display() override {
        std::cout << "๐Ÿ–ผ๏ธ ์ด๋ฏธ์ง€ ํ‘œ์‹œ: " << filename << std::endl;
    }
    
    std::string getFilename() const override { return filename; }
};

// ํ”„๋ก์‹œ - ์‹ค์ œ ๊ฐ์ฒด ์ƒ์„ฑ์„ ์ง€์—ฐ์‹œํ‚ด
class ImageProxy : public Image {
private:
    std::string filename;
    mutable std::unique_ptr<RealImage> realImage; // ์‹ค์ œ ์ด๋ฏธ์ง€ (์ง€์—ฐ ์ƒ์„ฑ)
    
public:
    ImageProxy(const std::string& file) : filename(file) {
        std::cout << "๐Ÿ“‹ ํ”„๋ก์‹œ ์ƒ์„ฑ: " << filename << " (์•„์ง ๋กœ๋”ฉ ์•ˆ ํ•จ)" << std::endl;
    }
    
    void display() override {
        // ์ฒ˜์Œ display() ํ˜ธ์ถœ ์‹œ์—๋งŒ ์‹ค์ œ ์ด๋ฏธ์ง€ ์ƒ์„ฑ
        if (!realImage) {
            std::cout << "โณ ํ•„์š”ํ•  ๋•Œ ๋กœ๋”ฉ ์‹œ์ž‘..." << std::endl;
            realImage = std::make_unique<RealImage>(filename);
        }
        realImage->display();
    }
    
    std::string getFilename() const override { return filename; }
};

int main() {
    std::cout << "=== ์ด๋ฏธ์ง€ ๋ชฉ๋ก ์ƒ์„ฑ ===" << std::endl;
    // ํ”„๋ก์‹œ๋Š” ์ฆ‰์‹œ ์ƒ์„ฑ๋˜์ง€๋งŒ ์‹ค์ œ ์ด๋ฏธ์ง€๋Š” ์•„์ง ๋กœ๋”ฉ ์•ˆ ๋จ
    ImageProxy img1("photo1.jpg");
    ImageProxy img2("photo2.jpg");
    ImageProxy img3("photo3.jpg");
    
    std::cout << "\n=== ์ฒซ ๋ฒˆ์งธ ์ด๋ฏธ์ง€๋งŒ ํ‘œ์‹œ ===" << std::endl;
    img1.display(); // ์ด๋•Œ ์‹ค์ œ ๋กœ๋”ฉ ๋ฐœ์ƒ
    
    std::cout << "\n=== ์ฒซ ๋ฒˆ์งธ ์ด๋ฏธ์ง€ ๋‹ค์‹œ ํ‘œ์‹œ ===" << std::endl;
    img1.display(); // ์ด๋ฏธ ๋กœ๋”ฉ๋จ, ๋ฐ”๋กœ ํ‘œ์‹œ
    
    // img2, img3์€ display() ์•ˆ ๋ถˆ๋ €์œผ๋‹ˆ ๋กœ๋”ฉ ์•ˆ ๋จ = ๋ฉ”๋ชจ๋ฆฌ ์ ˆ์•ฝ!
    
    return 0;
}

๐ŸŽญ 3๋ถ€: ํ–‰๋™ ํŒจํ„ด (Behavioral Patterns)

ํ–‰๋™ ํŒจํ„ด์€ ๊ฐ์ฒด๋“ค์ด ์–ด๋–ป๊ฒŒ ์ƒํ˜ธ์ž‘์šฉํ•˜๊ณ  ์ฑ…์ž„์„ ๋ถ„๋ฐฐํ• ์ง€์— ๋Œ€ํ•œ ํ•ด๋‹ต์ด์•ผ.
11๊ฐ€์ง€๋กœ ๊ฐ€์žฅ ๋งŽ์€ ํŒจํ„ด์ด ์žˆ๋Š” ์นดํ…Œ๊ณ ๋ฆฌ! ๊ทธ ์ค‘ ๊ฐ€์žฅ ์ค‘์š”ํ•˜๊ณ  ์ž์ฃผ ์“ฐ์ด๋Š” ๊ฒƒ๋“ค ์œ„์ฃผ๋กœ ํŒŒํ—ค์ณ๋ณผ๊ฒŒ ๐Ÿ”ฅ

๐Ÿ‘๏ธ ๐Ÿ“‹ ๐ŸŽฏ ๐Ÿ”„ ๐Ÿ’พ ๐Ÿ“ก ๐Ÿงฉ
๐Ÿ‘๏ธ 3-1. Observer ํŒจํ„ด
ํ–‰๋™ ํŒจํ„ด ์ด๋ฒคํŠธ ์‹œ์Šคํ…œ 1:N ๊ด€๊ณ„

ํ•ต์‹ฌ ๊ฐœ๋…: ๊ฐ์ฒด์˜ ์ƒํƒœ ๋ณ€ํ™”๋ฅผ ๊ด€์ฐฐํ•˜๋Š” ์˜ต์ €๋ฒ„๋“ค์—๊ฒŒ ์ž๋™์œผ๋กœ ์•Œ๋ฆผ์„ ๋ณด๋‚ด๋Š” ํŒจํ„ด.
์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ, MVC ํŒจํ„ด์˜ Model-View ๊ด€๊ณ„, ์ฃผ์‹ ๊ฐ€๊ฒฉ ์•Œ๋ฆผ ์‹œ์Šคํ…œ ๋“ฑ์—์„œ ํ•ต์‹ฌ์ ์œผ๋กœ ์‚ฌ์šฉ๋ผ!
C++์—์„œ๋Š” std::function๊ณผ ๋žŒ๋‹ค๋ฅผ ํ™œ์šฉํ•˜๋ฉด ๋” ํ˜„๋Œ€์ ์œผ๋กœ ๊ตฌํ˜„ ๊ฐ€๋Šฅํ•จ!


// ๐Ÿ‘๏ธ Observer ํŒจํ„ด - ์ฃผ์‹ ๊ฐ€๊ฒฉ ์•Œ๋ฆผ ์‹œ์Šคํ…œ
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <functional>

// ์˜ต์ €๋ฒ„ ์ธํ„ฐํŽ˜์ด์Šค
class StockObserver {
public:
    virtual ~StockObserver() = default;
    virtual void onPriceChanged(const std::string& stock, double price) = 0;
};

// ์ฃผ์ œ (Subject) - ๊ด€์ฐฐ ๋Œ€์ƒ
class StockMarket {
private:
    std::vector<StockObserver*> observers;
    std::string stockName;
    double price;
    
public:
    StockMarket(const std::string& name, double initialPrice)
        : stockName(name), price(initialPrice) {}
    
    void addObserver(StockObserver* observer) {
        observers.push_back(observer);
        std::cout << "๐Ÿ“‹ ์˜ต์ €๋ฒ„ ๋“ฑ๋ก ์™„๋ฃŒ" << std::endl;
    }
    
    void removeObserver(StockObserver* observer) {
        observers.erase(
            std::remove(observers.begin(), observers.end(), observer),
            observers.end()
        );
    }
    
    void setPrice(double newPrice) {
        price = newPrice;
        std::cout << "\n๐Ÿ“ˆ " << stockName << " ๊ฐ€๊ฒฉ ๋ณ€๋™: " 
                  << newPrice << "์›" << std::endl;
        notifyObservers(); // ๋ชจ๋“  ์˜ต์ €๋ฒ„์—๊ฒŒ ์•Œ๋ฆผ!
    }
    
private:
    void notifyObservers() {
        for (auto* observer : observers) {
            observer->onPriceChanged(stockName, price);
        }
    }
};

// ๊ตฌ์ฒด ์˜ต์ €๋ฒ„๋“ค
class InvestorAlert : public StockObserver {
private:
    std::string name;
    double targetPrice;
    
public:
    InvestorAlert(const std::string& n, double target)
        : name(n), targetPrice(target) {}
    
    void onPriceChanged(const std::string& stock, double price) override {
        if (price >= targetPrice) {
            std::cout << "๐Ÿ”” [" << name << "] " << stock 
                      << " ๋ชฉํ‘œ๊ฐ€ ๋‹ฌ์„ฑ! ํ˜„์žฌ๊ฐ€: " << price << "์›" << std::endl;
        } else {
            std::cout << "๐Ÿ“Š [" << name << "] " << stock 
                      << " ํ˜„์žฌ๊ฐ€: " << price << "์› (๋ชฉํ‘œ: " 
                      << targetPrice << "์›)" << std::endl;
        }
    }
};

class StopLossAlert : public StockObserver {
private:
    double stopLossPrice;
    
public:
    StopLossAlert(double stopPrice) : stopLossPrice(stopPrice) {}
    
    void onPriceChanged(const std::string& stock, double price) override {
        if (price <= stopLossPrice) {
            std::cout << "๐Ÿšจ [์†์ ˆ ์•Œ๋ฆผ] " << stock 
                      << " ์†์ ˆ๊ฐ€ ๋„๋‹ฌ! ์ฆ‰์‹œ ๋งค๋„ ๊ถŒ๊ณ !" << std::endl;
        }
    }
};

int main() {
    StockMarket samsung("์‚ผ์„ฑ์ „์ž", 70000);
    
    InvestorAlert investor1("๊น€ํˆฌ์ž", 75000);
    InvestorAlert investor2("์ด์ฃผ์‹", 80000);
    StopLossAlert stopLoss(65000);
    
    samsung.addObserver(&investor1);
    samsung.addObserver(&investor2);
    samsung.addObserver(&stopLoss);
    
    samsung.setPrice(72000);
    samsung.setPrice(76000);
    samsung.setPrice(64000); // ์†์ ˆ๊ฐ€ ๋„๋‹ฌ!
    
    return 0;
}
๐ŸŽฏ 3-2. Strategy ํŒจํ„ด
ํ–‰๋™ ํŒจํ„ด ์•Œ๊ณ ๋ฆฌ์ฆ˜ ๊ต์ฒด OCP ์›์น™

ํ•ต์‹ฌ ๊ฐœ๋…: ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ์บก์Аํ™”ํ•˜๊ณ  ๋Ÿฐํƒ€์ž„์— ๊ต์ฒด ๊ฐ€๋Šฅํ•˜๊ฒŒ ๋งŒ๋“œ๋Š” ํŒจํ„ด.
์ •๋ ฌ ์•Œ๊ณ ๋ฆฌ์ฆ˜, ๊ฒฐ์ œ ๋ฐฉ๋ฒ•, ์••์ถ• ์•Œ๊ณ ๋ฆฌ์ฆ˜ ๋“ฑ "๋ฐฉ๋ฒ•"์ด ์—ฌ๋Ÿฌ ๊ฐ€์ง€์ผ ๋•Œ ๋”ฑ์ด์•ผ!
C++์—์„œ๋Š” std::function์ด๋‚˜ ๋žŒ๋‹ค๋กœ๋„ ๊ตฌํ˜„ ๊ฐ€๋Šฅํ•ด์„œ ๋” ์œ ์—ฐํ•˜๊ฒŒ ์“ธ ์ˆ˜ ์žˆ์Œ!


// ๐ŸŽฏ Strategy ํŒจํ„ด - ์ •๋ ฌ ์ „๋žต ์‹œ์Šคํ…œ
#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>
#include <string>

// ์ „๋žต ์ธํ„ฐํŽ˜์ด์Šค
class SortStrategy {
public:
    virtual ~SortStrategy() = default;
    virtual void sort(std::vector<int>& data) = 0;
    virtual std::string getName() const = 0;
};

// ๊ตฌ์ฒด ์ „๋žต๋“ค
class BubbleSortStrategy : public SortStrategy {
public:
    void sort(std::vector<int>& data) override {
        int n = data.size();
        for (int i = 0; i < n-1; i++) {
            for (int j = 0; j < n-i-1; j++) {
                if (data[j] > data[j+1]) {
                    std::swap(data[j], data[j+1]);
                }
            }
        }
    }
    std::string getName() const override { return "๋ฒ„๋ธ” ์ •๋ ฌ"; }
};

class QuickSortStrategy : public SortStrategy {
public:
    void sort(std::vector<int>& data) override {
        std::sort(data.begin(), data.end()); // ์‹ค์ œ๋กœ๋Š” ํ€ต์†ŒํŠธ ๊ตฌํ˜„
    }
    std::string getName() const override { return "ํ€ต ์ •๋ ฌ"; }
};

class ReverseSortStrategy : public SortStrategy {
public:
    void sort(std::vector<int>& data) override {
        std::sort(data.begin(), data.end(), std::greater<int>());
    }
    std::string getName() const override { return "์—ญ์ˆœ ์ •๋ ฌ"; }
};

// ์ปจํ…์ŠคํŠธ - ์ „๋žต์„ ์‚ฌ์šฉํ•˜๋Š” ํด๋ž˜์Šค
class DataSorter {
private:
    std::unique_ptr<SortStrategy> strategy;
    
public:
    DataSorter(std::unique_ptr<SortStrategy> s) : strategy(std::move(s)) {}
    
    // ๋Ÿฐํƒ€์ž„์— ์ „๋žต ๊ต์ฒด ๊ฐ€๋Šฅ!
    void setStrategy(std::unique_ptr<SortStrategy> s) {
        strategy = std::move(s);
    }
    
    void sortData(std::vector<int>& data) {
        std::cout << "๐Ÿ”„ " << strategy->getName() << " ์‚ฌ์šฉ ์ค‘..." << std::endl;
        strategy->sort(data);
        
        std::cout << "๊ฒฐ๊ณผ: ";
        for (int val : data) std::cout << val << " ";
        std::cout << std::endl;
    }
};

int main() {
    std::vector<int> data1 = {64, 34, 25, 12, 22, 11, 90};
    std::vector<int> data2 = data1;
    std::vector<int> data3 = data1;
    
    DataSorter sorter(std::make_unique<BubbleSortStrategy>());
    sorter.sortData(data1);
    
    // ์ „๋žต ๊ต์ฒด!
    sorter.setStrategy(std::make_unique<QuickSortStrategy>());
    sorter.sortData(data2);
    
    sorter.setStrategy(std::make_unique<ReverseSortStrategy>());
    sorter.sortData(data3);
    
    return 0;
}
๐Ÿ“‹ 3-3. Command ํŒจํ„ด
ํ–‰๋™ ํŒจํ„ด ์‹คํ–‰์ทจ์†Œ ์š”์ฒญ ์บก์Аํ™”

ํ•ต์‹ฌ ๊ฐœ๋…: ์š”์ฒญ์„ ๊ฐ์ฒด๋กœ ์บก์Аํ™”ํ•˜์—ฌ ๋งค๊ฐœ๋ณ€์ˆ˜ํ™”, ํ์ž‰, ๋กœ๊น…, ์‹คํ–‰์ทจ์†Œ(Undo)๋ฅผ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•˜๋Š” ํŒจํ„ด.
ํ…์ŠคํŠธ ์—๋””ํ„ฐ์˜ Ctrl+Z, ๊ฒŒ์ž„์˜ ์ปค๋งจ๋“œ ์‹œ์Šคํ…œ, ํŠธ๋žœ์žญ์…˜ ์ฒ˜๋ฆฌ์—์„œ ํ•ต์‹ฌ์ ์œผ๋กœ ์‚ฌ์šฉ๋ผ!


// ๐Ÿ“‹ Command ํŒจํ„ด - ํ…์ŠคํŠธ ์—๋””ํ„ฐ Undo/Redo
#include <iostream>
#include <string>
#include <stack>
#include <memory>

// ํ…์ŠคํŠธ ์—๋””ํ„ฐ (Receiver)
class TextEditor {
private:
    std::string text;
    
public:
    void insertText(const std::string& str, int pos) {
        text.insert(pos, str);
        std::cout << "โœ๏ธ ์‚ฝ์ž… ํ›„: \"" << text << "\"" << std::endl;
    }
    
    void deleteText(int pos, int length) {
        text.erase(pos, length);
        std::cout << "๐Ÿ—‘๏ธ ์‚ญ์ œ ํ›„: \"" << text << "\"" << std::endl;
    }
    
    std::string getText() const { return text; }
};

// ์ปค๋งจ๋“œ ์ธํ„ฐํŽ˜์ด์Šค
class Command {
public:
    virtual ~Command() = default;
    virtual void execute() = 0;
    virtual void undo() = 0;
};

// ๊ตฌ์ฒด ์ปค๋งจ๋“œ๋“ค
class InsertCommand : public Command {
private:
    TextEditor& editor;
    std::string text;
    int position;
    
public:
    InsertCommand(TextEditor& e, const std::string& t, int pos)
        : editor(e), text(t), position(pos) {}
    
    void execute() override {
        editor.insertText(text, position);
    }
    
    void undo() override {
        editor.deleteText(position, text.length());
        std::cout << "โ†ฉ๏ธ ์‚ฝ์ž… ์ทจ์†Œ" << std::endl;
    }
};

class DeleteCommand : public Command {
private:
    TextEditor& editor;
    std::string deletedText;
    int position;
    int length;
    
public:
    DeleteCommand(TextEditor& e, int pos, int len)
        : editor(e), position(pos), length(len) {
        deletedText = e.getText().substr(pos, len);
    }
    
    void execute() override {
        editor.deleteText(position, length);
    }
    
    void undo() override {
        editor.insertText(deletedText, position);
        std::cout << "โ†ฉ๏ธ ์‚ญ์ œ ์ทจ์†Œ" << std::endl;
    }
};

// ์ปค๋งจ๋“œ ๊ด€๋ฆฌ์ž (Invoker)
class CommandManager {
private:
    std::stack<std::unique_ptr<Command>> history;
    
public:
    void executeCommand(std::unique_ptr<Command> cmd) {
        cmd->execute();
        history.push(std::move(cmd));
    }
    
    void undo() {
        if (!history.empty()) {
            history.top()->undo();
            history.pop();
        } else {
            std::cout << "โš ๏ธ ์ทจ์†Œํ•  ์ž‘์—…์ด ์—†์Šต๋‹ˆ๋‹ค." << std::endl;
        }
    }
};

int main() {
    TextEditor editor;
    CommandManager manager;
    
    std::cout << "=== ํ…์ŠคํŠธ ํŽธ์ง‘ ===" << std::endl;
    manager.executeCommand(std::make_unique<InsertCommand>(editor, "Hello", 0));
    manager.executeCommand(std::make_unique<InsertCommand>(editor, " World", 5));
    manager.executeCommand(std::make_unique<InsertCommand>(editor, "!", 11));
    
    std::cout << "\n=== Undo 3๋ฒˆ ===" << std::endl;
    manager.undo();
    manager.undo();
    manager.undo();
    
    return 0;
}
๐Ÿ”„ 3-4. Iterator ํŒจํ„ด
ํ–‰๋™ ํŒจํ„ด ์ˆœํšŒ STL ํ•ต์‹ฌ

ํ•ต์‹ฌ ๊ฐœ๋…: ์ปฌ๋ ‰์…˜์˜ ๋‚ด๋ถ€ ๊ตฌ์กฐ๋ฅผ ๋…ธ์ถœํ•˜์ง€ ์•Š๊ณ  ์ˆœ์ฐจ์ ์œผ๋กœ ์ ‘๊ทผํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์ œ๊ณตํ•˜๋Š” ํŒจํ„ด.
C++ STL์˜ ์ดํ„ฐ๋ ˆ์ดํ„ฐ๊ฐ€ ๋ฐ”๋กœ ์ด ํŒจํ„ด์˜ ๊ตฌํ˜„์ฒด์•ผ! begin(), end(), ++ ์—ฐ์‚ฐ์ž ๋‹ค ์ด ํŒจํ„ด์ž„ ใ…‹ใ…‹


// ๐Ÿ”„ Iterator ํŒจํ„ด - ์ปค์Šคํ…€ ์ปฌ๋ ‰์…˜ ์ดํ„ฐ๋ ˆ์ดํ„ฐ
#include <iostream>
#include <stdexcept>

// ์ดํ„ฐ๋ ˆ์ดํ„ฐ ์ธํ„ฐํŽ˜์ด์Šค
template<typename T>
class Iterator {
public:
    virtual ~Iterator() = default;
    virtual bool hasNext() const = 0;
    virtual T next() = 0;
};

// ์ปค์Šคํ…€ ๋ฐฐ์—ด ์ปฌ๋ ‰์…˜
template<typename T>
class NumberCollection {
private:
    T* data;
    int size;
    int capacity;
    
public:
    NumberCollection(int cap) : size(0), capacity(cap) {
        data = new T[capacity];
    }
    
    ~NumberCollection() { delete[] data; }
    
    void add(T value) {
        if (size < capacity) data[size++] = value;
    }
    
    T get(int index) const { return data[index]; }
    int getSize() const { return size; }
    
    // ์ดํ„ฐ๋ ˆ์ดํ„ฐ ํด๋ž˜์Šค (๋‚ด๋ถ€ ํด๋ž˜์Šค)
    class NumberIterator : public Iterator<T> {
    private:
        const NumberCollection<T>& collection;
        int current = 0;
        
    public:
        NumberIterator(const NumberCollection<T>& c) : collection(c) {}
        
        bool hasNext() const override {
            return current < collection.getSize();
        }
        
        T next() override {
            if (!hasNext()) throw std::out_of_range("๋” ์ด์ƒ ์š”์†Œ ์—†์Œ");
            return collection.get(current++);
        }
    };
    
    NumberIterator createIterator() const {
        return NumberIterator(*this);
    }
};

int main() {
    NumberCollection<int> numbers(10);
    numbers.add(10);
    numbers.add(20);
    numbers.add(30);
    numbers.add(40);
    numbers.add(50);
    
    auto it = numbers.createIterator();
    
    std::cout << "๐Ÿ”„ ์ดํ„ฐ๋ ˆ์ดํ„ฐ๋กœ ์ˆœํšŒ: ";
    while (it.hasNext()) {
        std::cout << it.next() << " ";
    }
    std::cout << std::endl;
    
    return 0;
}
๐ŸŽญ 3-5. State ํŒจํ„ด
ํ–‰๋™ ํŒจํ„ด ์ƒํƒœ ๊ธฐ๊ณ„ ์กฐ๊ฑด๋ฌธ ์ œ๊ฑฐ

ํ•ต์‹ฌ ๊ฐœ๋…: ๊ฐ์ฒด์˜ ๋‚ด๋ถ€ ์ƒํƒœ์— ๋”ฐ๋ผ ํ–‰๋™์ด ๋‹ฌ๋ผ์ง€๋„๋ก ํ•˜๋Š” ํŒจํ„ด. ๊ฑฐ๋Œ€ํ•œ if-else๋‚˜ switch ๋ฌธ์„ ์ œ๊ฑฐํ•  ์ˆ˜ ์žˆ์–ด!
์žํŒ๊ธฐ, ์‹ ํ˜ธ๋“ฑ, ๊ฒŒ์ž„ ์บ๋ฆญํ„ฐ ์ƒํƒœ ๊ด€๋ฆฌ ๋“ฑ์—์„œ ์ž์ฃผ ์”€.


// ๐ŸŽญ State ํŒจํ„ด - ์žํŒ๊ธฐ ์ƒํƒœ ๊ด€๋ฆฌ
#include <iostream>
#include <memory>
#include <string>

class VendingMachine; // ์ „๋ฐฉ ์„ ์–ธ

// ์ƒํƒœ ์ธํ„ฐํŽ˜์ด์Šค
class State {
public:
    virtual ~State() = default;
    virtual void insertCoin(VendingMachine& machine) = 0;
    virtual void selectProduct(VendingMachine& machine) = 0;
    virtual void dispense(VendingMachine& machine) = 0;
    virtual std::string getStateName() const = 0;
};

// ์žํŒ๊ธฐ (Context)
class VendingMachine {
private:
    std::unique_ptr<State> currentState;
    int stock;
    
public:
    VendingMachine(int initialStock);
    
    void setState(std::unique_ptr<State> state) {
        currentState = std::move(state);
        std::cout << "๐Ÿ”„ ์ƒํƒœ ๋ณ€๊ฒฝ: " << currentState->getStateName() << std::endl;
    }
    
    void insertCoin() { currentState->insertCoin(*this); }
    void selectProduct() { currentState->selectProduct(*this); }
    void dispense() { currentState->dispense(*this); }
    
    int getStock() const { return stock; }
    void decreaseStock() { stock--; }
};

// ๊ตฌ์ฒด ์ƒํƒœ๋“ค
class IdleState : public State {
public:
    void insertCoin(VendingMachine& machine) override;
    void selectProduct(VendingMachine& machine) override {
        std::cout << "โš ๏ธ ๋จผ์ € ๋™์ „์„ ๋„ฃ์–ด์ฃผ์„ธ์š”!" << std::endl;
    }
    void dispense(VendingMachine& machine) override {
        std::cout << "โš ๏ธ ๋™์ „์„ ๋จผ์ € ๋„ฃ์–ด์ฃผ์„ธ์š”!" << std::endl;
    }
    std::string getStateName() const override { return "๋Œ€๊ธฐ ์ƒํƒœ"; }
};

class HasCoinState : public State {
public:
    void insertCoin(VendingMachine& machine) override {
        std::cout << "โš ๏ธ ์ด๋ฏธ ๋™์ „์ด ๋“ค์–ด์žˆ์Šต๋‹ˆ๋‹ค!" << std::endl;
    }
    void selectProduct(VendingMachine& machine) override;
    void dispense(VendingMachine& machine) override {
        std::cout << "โš ๏ธ ๋จผ์ € ์ƒํ’ˆ์„ ์„ ํƒํ•ด์ฃผ์„ธ์š”!" << std::endl;
    }
    std::string getStateName() const override { return "๋™์ „ ํˆฌ์ž… ์ƒํƒœ"; }
};

class DispensingState : public State {
public:
    void insertCoin(VendingMachine& machine) override {
        std::cout << "โš ๏ธ ์ƒํ’ˆ ๋ฐฐ์ถœ ์ค‘์ž…๋‹ˆ๋‹ค!" << std::endl;
    }
    void selectProduct(VendingMachine& machine) override {
        std::cout << "โš ๏ธ ์ƒํ’ˆ ๋ฐฐ์ถœ ์ค‘์ž…๋‹ˆ๋‹ค!" << std::endl;
    }
    void dispense(VendingMachine& machine) override;
    std::string getStateName() const override { return "๋ฐฐ์ถœ ์ƒํƒœ"; }
};

// ์ƒํƒœ ์ „ํ™˜ ๊ตฌํ˜„
void IdleState::insertCoin(VendingMachine& machine) {
    std::cout << "๐Ÿ’ฐ ๋™์ „ ํˆฌ์ž…!" << std::endl;
    machine.setState(std::make_unique<HasCoinState>());
}

void HasCoinState::selectProduct(VendingMachine& machine) {
    std::cout << "๐ŸŽฏ ์ƒํ’ˆ ์„ ํƒ!" << std::endl;
    machine.setState(std::make_unique<DispensingState>());
}

void DispensingState::dispense(VendingMachine& machine) {
    if (machine.getStock() > 0) {
        machine.decreaseStock();
        std::cout << "๐Ÿฅค ์ƒํ’ˆ ๋ฐฐ์ถœ ์™„๋ฃŒ!" << std::endl;
        machine.setState(std::make_unique<IdleState>());
    } else {
        std::cout << "โŒ ์žฌ๊ณ  ์—†์Œ!" << std::endl;
        machine.setState(std::make_unique<IdleState>());
    }
}

VendingMachine::VendingMachine(int initialStock) : stock(initialStock) {
    currentState = std::make_unique<IdleState>();
    std::cout << "๐Ÿช ์žํŒ๊ธฐ ์ดˆ๊ธฐํ™” (์žฌ๊ณ : " << stock << "๊ฐœ)" << std::endl;
}

int main() {
    VendingMachine machine(3);
    
    std::cout << "\n=== ์ •์ƒ ๊ตฌ๋งค ===" << std::endl;
    machine.insertCoin();
    machine.selectProduct();
    machine.dispense();
    
    std::cout << "\n=== ์ž˜๋ชป๋œ ์ˆœ์„œ ===" << std::endl;
    machine.selectProduct(); // ๋™์ „ ์—†์ด ์„ ํƒ ์‹œ๋„
    machine.insertCoin();
    machine.insertCoin(); // ์ค‘๋ณต ํˆฌ์ž… ์‹œ๋„
    machine.selectProduct();
    machine.dispense();
    
    return 0;
}
๐Ÿ“ 3-6. Template Method ํŒจํ„ด
ํ–‰๋™ ํŒจํ„ด ์•Œ๊ณ ๋ฆฌ์ฆ˜ ๊ณจ๊ฒฉ ํ›… ๋ฉ”์„œ๋“œ

ํ•ต์‹ฌ ๊ฐœ๋…: ์•Œ๊ณ ๋ฆฌ์ฆ˜์˜ ๊ณจ๊ฒฉ์„ ์ •์˜ํ•˜๊ณ , ์ผ๋ถ€ ๋‹จ๊ณ„๋ฅผ ์„œ๋ธŒํด๋ž˜์Šค์—์„œ ๊ตฌํ˜„ํ•˜๋„๋ก ํ•˜๋Š” ํŒจํ„ด.
"ํ—๋ฆฌ์šฐ๋“œ ์›์น™ - Don't call us, we'll call you"๋ฅผ ๊ตฌํ˜„ํ•œ ํŒจํ„ด์ด์•ผ!


// ๐Ÿ“ Template Method ํŒจํ„ด - ์Œ๋ฃŒ ์ œ์กฐ ํ”„๋กœ์„ธ์Šค
#include <iostream>
#include <string>

class BeverageMaker {
public:
    // ํ…œํ”Œ๋ฆฟ ๋ฉ”์„œ๋“œ - ์•Œ๊ณ ๋ฆฌ์ฆ˜ ๊ณจ๊ฒฉ ์ •์˜ (final๋กœ ์˜ค๋ฒ„๋ผ์ด๋“œ ๋ฐฉ์ง€)
    void makeBeverage() {
        boilWater();
        brew();          // ์„œ๋ธŒํด๋ž˜์Šค์—์„œ ๊ตฌํ˜„
        pourInCup();
        if (customerWantsCondiments()) { // ํ›… ๋ฉ”์„œ๋“œ
            addCondiments(); // ์„œ๋ธŒํด๋ž˜์Šค์—์„œ ๊ตฌํ˜„
        }
        std::cout << "โœ… " << getBeverageName() << " ์™„์„ฑ!" << std::endl;
    }
    
    virtual ~BeverageMaker() = default;

protected:
    void boilWater() {
        std::cout << "๐Ÿ’ง ๋ฌผ ๋“์ด๋Š” ์ค‘..." << std::endl;
    }
    
    void pourInCup() {
        std::cout << "โ˜• ์ปต์— ๋”ฐ๋ฅด๋Š” ์ค‘..." << std::endl;
    }
    
    // ์„œ๋ธŒํด๋ž˜์Šค์—์„œ ๋ฐ˜๋“œ์‹œ ๊ตฌํ˜„ํ•ด์•ผ ํ•˜๋Š” ์ถ”์ƒ ๋ฉ”์„œ๋“œ
    virtual void brew() = 0;
    virtual void addCondiments() = 0;
    virtual std::string getBeverageName() const = 0;
    
    // ํ›… ๋ฉ”์„œ๋“œ - ์„ ํƒ์ ์œผ๋กœ ์˜ค๋ฒ„๋ผ์ด๋“œ ๊ฐ€๋Šฅ
    virtual bool customerWantsCondiments() const { return true; }
};

class CoffeeMaker : public BeverageMaker {
protected:
    void brew() override {
        std::cout << "โ˜• ์ปคํ”ผ ์›๋‘ ์šฐ๋ ค๋‚ด๋Š” ์ค‘..." << std::endl;
    }
    
    void addCondiments() override {
        std::cout << "๐Ÿฅ› ์„คํƒ•๊ณผ ์šฐ์œ  ์ถ”๊ฐ€!" << std::endl;
    }
    
    std::string getBeverageName() const override { return "์ปคํ”ผ"; }
};

class TeaMaker : public BeverageMaker {
protected:
    void brew() override {
        std::cout << "๐Ÿต ์ฐจ ์šฐ๋ ค๋‚ด๋Š” ์ค‘..." << std::endl;
    }
    
    void addCondiments() override {
        std::cout << "๐Ÿ‹ ๋ ˆ๋ชฌ ์ถ”๊ฐ€!" << std::endl;
    }
    
    std::string getBeverageName() const override { return "์ฐจ"; }
    
    // ํ›… ๋ฉ”์„œ๋“œ ์˜ค๋ฒ„๋ผ์ด๋“œ - ์ด ์ฐจ๋Š” ์ฒจ๊ฐ€๋ฌผ ์—†์ด!
    bool customerWantsCondiments() const override { return false; }
};

int main() {
    std::cout << "=== ์ปคํ”ผ ๋งŒ๋“ค๊ธฐ ===" << std::endl;
    CoffeeMaker coffee;
    coffee.makeBeverage();
    
    std::cout << "\n=== ์ฐจ ๋งŒ๋“ค๊ธฐ ===" << std::endl;
    TeaMaker tea;
    tea.makeBeverage();
    
    return 0;
}

๐Ÿ“Š GoF ํŒจํ„ด ๋น„๊ต ์ •๋ฆฌํ‘œ
ํŒจํ„ด๋ช… ๋ถ„๋ฅ˜ ํ•ต์‹ฌ ๋ชฉ์  ์ฃผ์š” ์‚ฌ์šฉ์ฒ˜
Singleton ์ƒ์„ฑ ๋‹จ์ผ ์ธ์Šคํ„ด์Šค ๋ณด์žฅ ๋กœ๊ฑฐ, DB ์—ฐ๊ฒฐ, ์„ค์ • ๊ด€๋ฆฌ
Factory Method ์ƒ์„ฑ ๊ฐ์ฒด ์ƒ์„ฑ์„ ์„œ๋ธŒํด๋ž˜์Šค์— ์œ„์ž„ ํ”„๋ ˆ์ž„์›Œํฌ, ํ”Œ๋Ÿฌ๊ทธ์ธ ์‹œ์Šคํ…œ
Abstract Factory ์ƒ์„ฑ ๊ด€๋ จ ๊ฐ์ฒด๊ตฐ ์ƒ์„ฑ UI ํ…Œ๋งˆ, ํฌ๋กœ์Šค ํ”Œ๋žซํผ
Builder ์ƒ์„ฑ ๋ณต์žกํ•œ ๊ฐ์ฒด ๋‹จ๊ณ„๋ณ„ ์ƒ์„ฑ ์ฟผ๋ฆฌ ๋นŒ๋”, ์„ค์ • ๊ฐ์ฒด
Prototype ์ƒ์„ฑ ๊ธฐ์กด ๊ฐ์ฒด ๋ณต์ œ ๊ฒŒ์ž„ ์˜ค๋ธŒ์ ํŠธ, ์บ์‹ฑ
Adapter ๊ตฌ์กฐ ์ธํ„ฐํŽ˜์ด์Šค ๋ณ€ํ™˜ ๋ ˆ๊ฑฐ์‹œ ์ฝ”๋“œ ์—ฐ๋™
Decorator ๊ตฌ์กฐ ๋™์  ๊ธฐ๋Šฅ ์ถ”๊ฐ€ I/O ์ŠคํŠธ๋ฆผ, ๋ฏธ๋“ค์›จ์–ด
Facade ๊ตฌ์กฐ ๋ณต์žก์„ฑ ์ˆจ๊ธฐ๊ธฐ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋ž˜ํผ
Proxy ๊ตฌ์กฐ ์ ‘๊ทผ ์ œ์–ด/์ง€์—ฐ ๋กœ๋”ฉ ์บ์‹ฑ, ๋ณด์•ˆ, ์›๊ฒฉ ๊ฐ์ฒด
Observer ํ–‰๋™ 1:N ์ด๋ฒคํŠธ ์•Œ๋ฆผ ์ด๋ฒคํŠธ ์‹œ์Šคํ…œ, MVC
Strategy ํ–‰๋™ ์•Œ๊ณ ๋ฆฌ์ฆ˜ ๊ต์ฒด ์ •๋ ฌ, ๊ฒฐ์ œ, ์••์ถ•
Command ํ–‰๋™ ์š”์ฒญ ์บก์Аํ™” Undo/Redo, ํŠธ๋žœ์žญ์…˜
State ํ–‰๋™ ์ƒํƒœ๋ณ„ ํ–‰๋™ ๋ณ€๊ฒฝ ์ƒํƒœ ๊ธฐ๊ณ„, ๊ฒŒ์ž„ AI
Template Method ํ–‰๋™ ์•Œ๊ณ ๋ฆฌ์ฆ˜ ๊ณจ๊ฒฉ ์ •์˜ ํ”„๋ ˆ์ž„์›Œํฌ, ํ›… ๋ฉ”์„œ๋“œ
Iterator ํ–‰๋™ ์ปฌ๋ ‰์…˜ ์ˆœํšŒ STL ์ดํ„ฐ๋ ˆ์ดํ„ฐ

๐Ÿš€ 4๋ถ€: ํ˜„๋Œ€ C++์—์„œ์˜ ๋””์ž์ธ ํŒจํ„ด ํ™œ์šฉ

C++11 ์ดํ›„๋กœ ์–ธ์–ด ์ž์ฒด๊ฐ€ ๋งŽ์ด ๋ฐœ์ „ํ•˜๋ฉด์„œ ๋””์ž์ธ ํŒจํ„ด ๊ตฌํ˜„ ๋ฐฉ์‹๋„ ๋‹ฌ๋ผ์กŒ์–ด!
std::function, ๋žŒ๋‹ค, std::unique_ptr, std::shared_ptr, ๊ฐ€๋ณ€ ํ…œํ”Œ๋ฆฟ ๋“ฑ์„ ํ™œ์šฉํ•˜๋ฉด
๋” ๊ฐ„๊ฒฐํ•˜๊ณ  ์•ˆ์ „ํ•œ ํŒจํ„ด ๊ตฌํ˜„์ด ๊ฐ€๋Šฅํ•ด์ง ๐Ÿ˜Ž

MODERN C++ DESIGN PATTERNS ๐Ÿš€ ํ˜„๋Œ€ C++ ํŒจํ„ด ๊ตฌํ˜„์˜ ์ง„ํ™” ๐Ÿง  ์Šค๋งˆํŠธ ํฌ์ธํ„ฐ unique_ptr / shared_ptr โ€ข ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜ ๋ฐฉ์ง€ โ€ข RAII ํŒจํ„ด ์ž๋™ ์ ์šฉ โ€ข ์†Œ์œ ๊ถŒ ๋ช…ํ™•ํžˆ ํ‘œํ˜„ โ€ข Factory ํŒจํ„ด์—์„œ make_unique ํ™œ์šฉ โ€ข Observer์—์„œ weak_ptr ๋กœ ์ˆœํ™˜ ์ฐธ์กฐ ๋ฐฉ์ง€ โšก ๋žŒ๋‹ค & std::function ํ•จ์ˆ˜ํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์Šคํƒ€์ผ โ€ข Strategy๋ฅผ ๋žŒ๋‹ค๋กœ ํ‘œํ˜„ โ€ข Command๋ฅผ ํ•จ์ˆ˜๋กœ ์ €์žฅ โ€ข Observer ์ฝœ๋ฐฑ ๋“ฑ๋ก โ€ข ํด๋ž˜์Šค ์—†์ด ๊ฐ„๊ฒฐํ•˜๊ฒŒ ํŒจํ„ด ๊ตฌํ˜„ ๊ฐ€๋Šฅ โ€ข ์บก์ฒ˜๋กœ ์ƒํƒœ ์œ ์ง€ ๐Ÿ”ง ํ…œํ”Œ๋ฆฟ & ์ œ๋„ค๋ฆญ ์ปดํŒŒ์ผ ํƒ€์ž„ ํŒจํ„ด โ€ข CRTP๋กœ ์ •์  ๋‹คํ˜•์„ฑ โ€ข Policy-based Design โ€ข ํƒ€์ž… ์•ˆ์ „ํ•œ Factory โ€ข ๊ฐ€๋ณ€ ํ…œํ”Œ๋ฆฟ์œผ๋กœ ์œ ์—ฐํ•œ Builder โ€ข ๋Ÿฐํƒ€์ž„ ์˜ค๋ฒ„ํ—ค๋“œ ์—†์Œ ๐ŸŽฏ Move Semantics ์ด๋™ ์˜๋ฏธ๋ก  ํ™œ์šฉ โ€ข Builder์—์„œ std::move โ€ข Factory ๋ฐ˜ํ™˜ ์ตœ์ ํ™” โ€ข Command ๊ฐ์ฒด ์ด๋™ โ€ข ๋ถˆํ•„์š”ํ•œ ๋ณต์‚ฌ ์ œ๊ฑฐ โ€ข ์„ฑ๋Šฅ ๋Œ€ํญ ํ–ฅ์ƒ โ€ข RVO/NRVO ์ตœ์ ํ™” C++11 / C++14 / C++17 / C++20 - ํ˜„๋Œ€ C++์€ ํŒจํ„ด ๊ตฌํ˜„์„ ๋” ๊ฐ„๊ฒฐํ•˜๊ณ  ์•ˆ์ „ํ•˜๊ฒŒ ๋งŒ๋“ค์–ด์ค˜!

ํ˜„๋Œ€ C++์—์„œ Strategy ํŒจํ„ด์„ ๋žŒ๋‹ค๋กœ ๊ตฌํ˜„ํ•˜๋ฉด ์ด๋ ‡๊ฒŒ ํ›จ์”ฌ ๊ฐ„๊ฒฐํ•ด์ ธ!


// โšก ํ˜„๋Œ€ C++ - ๋žŒ๋‹ค๋กœ Strategy ํŒจํ„ด ๊ตฌํ˜„
#include <iostream>
#include <functional>
#include <vector>
#include <algorithm>

class ModernSorter {
private:
    // std::function์œผ๋กœ ์ „๋žต ์ €์žฅ
    std::function<bool(int, int)> compareStrategy;
    
public:
    // ๋žŒ๋‹ค๋‚˜ ํ•จ์ˆ˜ ํฌ์ธํ„ฐ๋ฅผ ์ „๋žต์œผ๋กœ ๋ฐ›์Œ
    ModernSorter(std::function<bool(int, int)> strategy) 
        : compareStrategy(strategy) {}
    
    void sort(std::vector<int>& data) {
        std::sort(data.begin(), data.end(), compareStrategy);
    }
};

// CRTP (Curiously Recurring Template Pattern) - ์ •์  ๋‹คํ˜•์„ฑ
template<typename Derived>
class CRTPBase {
public:
    void interface() {
        static_cast<Derived*>(this)->implementation();
    }
};

class CRTPDerived : public CRTPBase<CRTPDerived> {
public:
    void implementation() {
        std::cout << "๐ŸŽฏ CRTP: ๊ฐ€์ƒํ•จ์ˆ˜ ์—†์ด ๋‹คํ˜•์„ฑ ๊ตฌํ˜„!" << std::endl;
    }
};

int main() {
    std::vector<int> data = {5, 2, 8, 1, 9, 3};
    
    // ๋žŒ๋‹ค๋กœ ์˜ค๋ฆ„์ฐจ์ˆœ ์ „๋žต
    ModernSorter ascSorter([](int a, int b) { return a < b; });
    ascSorter.sort(data);
    std::cout << "์˜ค๋ฆ„์ฐจ์ˆœ: ";
    for (int v : data) std::cout << v << " ";
    std::cout << std::endl;
    
    // ๋žŒ๋‹ค๋กœ ๋‚ด๋ฆผ์ฐจ์ˆœ ์ „๋žต
    ModernSorter descSorter([](int a, int b) { return a > b; });
    descSorter.sort(data);
    std::cout << "๋‚ด๋ฆผ์ฐจ์ˆœ: ";
    for (int v : data) std::cout << v << " ";
    std::cout << std::endl;
    
    // CRTP ์‚ฌ์šฉ
    CRTPDerived obj;
    obj.interface();
    
    return 0;
}
๐ŸŒŸ CRTP (Curiously Recurring Template Pattern)
CRTP๋Š” GoF ํŒจํ„ด์€ ์•„๋‹ˆ์ง€๋งŒ C++์—์„œ ๋งค์šฐ ์ค‘์š”ํ•œ ์ด๋””์—„์ด์•ผ. ๊ฐ€์ƒํ•จ์ˆ˜ ์—†์ด ์ปดํŒŒ์ผ ํƒ€์ž„์— ๋‹คํ˜•์„ฑ์„ ๊ตฌํ˜„ํ•ด์„œ ๋Ÿฐํƒ€์ž„ ์˜ค๋ฒ„ํ—ค๋“œ๊ฐ€ ์—†์–ด! ์„ฑ๋Šฅ์ด ์ค‘์š”ํ•œ ๊ฒŒ์ž„ ์—”์ง„์ด๋‚˜ ์ž„๋ฒ ๋””๋“œ ์‹œ์Šคํ…œ์—์„œ ์ž์ฃผ ์”€.

๐Ÿ’ก 5๋ถ€: ํŒจํ„ด ์„ ํƒ ๊ฐ€์ด๋“œ & ์‹ค์ „ ํŒ

ํŒจํ„ด์„ ์•Œ์•˜๋‹ค๊ณ  ๋‹ค๊ฐ€ ์•„๋‹ˆ์•ผ! ์–ธ์ œ ์–ด๋–ค ํŒจํ„ด์„ ์จ์•ผ ํ•˜๋Š”์ง€๊ฐ€ ์ง„์งœ ์‹ค๋ ฅ์ด๊ฑฐ๋“  ใ…‹ใ…‹
ํ˜„์—…์—์„œ ์ž์ฃผ ๋งˆ์ฃผ์น˜๋Š” ์ƒํ™ฉ๋ณ„๋กœ ์–ด๋–ค ํŒจํ„ด์„ ์„ ํƒํ•ด์•ผ ํ•˜๋Š”์ง€ ์ •๋ฆฌํ•ด๋ดค์–ด!

๐ŸŽฏ ํŒจํ„ด ์„ ํƒ ์ฒดํฌ๋ฆฌ์ŠคํŠธ

๊ฐ์ฒด ์ƒ์„ฑ ๊ด€๋ จ ๋ฌธ์ œ?
โ†’ ์ธ์Šคํ„ด์Šค ํ•˜๋‚˜๋งŒ ํ•„์š” โ†’ Singleton
โ†’ ์–ด๋–ค ํด๋ž˜์Šค ๋งŒ๋“ค์ง€ ๋ชจ๋ฆ„ โ†’ Factory Method
โ†’ ๊ด€๋ จ ๊ฐ์ฒด๋“ค ๋ฌถ์–ด์„œ ์ƒ์„ฑ โ†’ Abstract Factory
โ†’ ์ƒ์„ฑ์ž ํŒŒ๋ผ๋ฏธํ„ฐ ๋„ˆ๋ฌด ๋งŽ์Œ โ†’ Builder
โ†’ ๋น„์Šทํ•œ ๊ฐ์ฒด ๋งŽ์ด ํ•„์š” โ†’ Prototype

๊ตฌ์กฐ/์กฐํ•ฉ ๊ด€๋ จ ๋ฌธ์ œ?
โ†’ ์ธํ„ฐํŽ˜์ด์Šค ์•ˆ ๋งž์Œ โ†’ Adapter
โ†’ ๊ธฐ๋Šฅ ๋™์ ์œผ๋กœ ์ถ”๊ฐ€ โ†’ Decorator
โ†’ ๋ณต์žกํ•œ ์‹œ์Šคํ…œ ๋‹จ์ˆœํ™” โ†’ Facade
โ†’ ์ ‘๊ทผ ์ œ์–ด/์ง€์—ฐ ๋กœ๋”ฉ โ†’ Proxy

ํ–‰๋™/์•Œ๊ณ ๋ฆฌ์ฆ˜ ๊ด€๋ จ ๋ฌธ์ œ?
โ†’ ์ƒํƒœ ๋ณ€ํ™” ์•Œ๋ฆผ ํ•„์š” โ†’ Observer
โ†’ ์•Œ๊ณ ๋ฆฌ์ฆ˜ ๊ต์ฒด ํ•„์š” โ†’ Strategy
โ†’ Undo/Redo ํ•„์š” โ†’ Command
โ†’ ์ƒํƒœ์— ๋”ฐ๋ผ ํ–‰๋™ ๋‹ค๋ฆ„ โ†’ State
โ†’ ์•Œ๊ณ ๋ฆฌ์ฆ˜ ๊ณจ๊ฒฉ ๊ณ ์ • โ†’ Template Method
โš ๏ธ ํŒจํ„ด ๋‚จ์šฉ ์ฃผ์˜์‚ฌํ•ญ!

๋””์ž์ธ ํŒจํ„ด์€ ๋„๊ตฌ์•ผ, ๋ชฉ์ ์ด ์•„๋‹ˆ์•ผ! ๋‹ค์Œ ์ƒํ™ฉ์—์„œ๋Š” ํŒจํ„ด ์ ์šฉ์„ ์žฌ๊ณ ํ•ด๋ด:

โ€ข Over-engineering: ๊ฐ„๋‹จํ•œ ๋ฌธ์ œ์— ๋ณต์žกํ•œ ํŒจํ„ด ์ ์šฉ โ†’ ์ฝ”๋“œ๋งŒ ๋ณต์žกํ•ด์ง
โ€ข Pattern Fever: ๋ชจ๋“  ๊ณณ์— ํŒจํ„ด ์ ์šฉํ•˜๋ ค๋Š” ์š•์‹ฌ โ†’ ์œ ์ง€๋ณด์ˆ˜ ์ง€์˜ฅ
โ€ข Premature Abstraction: ์•„์ง ํ•„์š”ํ•˜์ง€ ์•Š์€ ์œ ์—ฐ์„ฑ์„ ์œ„ํ•ด ํŒจํ„ด ์ ์šฉ

"Make it work, make it right, make it fast" - ๋จผ์ € ๋™์ž‘ํ•˜๊ฒŒ ๋งŒ๋“ค๊ณ , ๊ทธ ๋‹ค์Œ์— ํŒจํ„ด์„ ๊ณ ๋ คํ•ด!
๐Ÿ† GoF ํŒจํ„ด ๋งˆ์Šคํ„ฐ๋ฅผ ์œ„ํ•œ ํ•™์Šต ๋กœ๋“œ๋งต

1๋‹จ๊ณ„ (์ž…๋ฌธ): Singleton, Factory Method, Observer, Strategy ๋จผ์ € ์ตํžˆ๊ธฐ
2๋‹จ๊ณ„ (์ค‘๊ธ‰): Decorator, Command, Builder, Facade ํ•™์Šต
3๋‹จ๊ณ„ (๊ณ ๊ธ‰): Abstract Factory, Composite, Proxy, State, Template Method
4๋‹จ๊ณ„ (์‹ฌํ™”): ๋‚˜๋จธ์ง€ ํŒจํ„ด + ํŒจํ„ด ์กฐํ•ฉ + ํ˜„๋Œ€ C++ ์ด๋””์—„ ์ ์šฉ

๐Ÿ’ก ์ถ”์ฒœ ํ•™์Šต๋ฒ•: ํŒจํ„ด ํ•˜๋‚˜๋ฅผ ๋ฐฐ์šธ ๋•Œ๋งˆ๋‹ค ์‹ค์ œ ํ”„๋กœ์ ํŠธ์— ์ ์šฉํ•ด๋ณด๋Š” ๊ฒŒ ์ตœ๊ณ ์•ผ!
์žฌ๋Šฅ๋„ท์—์„œ C++ ๊ด€๋ จ ๋ฉ˜ํ† ๋ง์„ ์ฐพ์•„๋ณด๋Š” ๊ฒƒ๋„ ์ข‹์€ ๋ฐฉ๋ฒ•์ด์•ผ - ์‹ค๋ฌด ๊ฒฝํ—˜์ž์—๊ฒŒ ์ง์ ‘ ๋ฐฐ์šฐ๋ฉด ์ดํ•ด๊ฐ€ ํ›จ์”ฌ ๋น ๋ฅด๊ฑฐ๋“ ! ๐Ÿš€

SUMMARY ๐ŸŽ“ GoF 23๊ฐ€์ง€ ํŒจํ„ด ์™„์ „ ์ •๋ณต ์ฒดํฌ๋ฆฌ์ŠคํŠธ ๐Ÿญ ์ƒ์„ฑ ํŒจํ„ด (5๊ฐœ) Singleton ๋‹จ์ผ ์ธ์Šคํ„ด์Šค Factory Method ์ƒ์„ฑ ์œ„์ž„ Abstract Factory ์ œํ’ˆ๊ตฐ ์ƒ์„ฑ Builder ๋‹จ๊ณ„๋ณ„ ์ƒ์„ฑ Prototype ๋ณต์ œ ๊ธฐ๋ฐ˜ ๐Ÿ”ง ๊ตฌ์กฐ ํŒจํ„ด (7๊ฐœ) Adapter ์ธํ„ฐํŽ˜์ด์Šค ๋ณ€ํ™˜ Bridge ์ถ”์ƒํ™”/๊ตฌํ˜„ ๋ถ„๋ฆฌ Composite ํŠธ๋ฆฌ ๊ตฌ์กฐ Decorator ๋™์  ๊ธฐ๋Šฅ ์ถ”๊ฐ€ Facade ๋ณต์žก์„ฑ ์ˆจ๊ธฐ๊ธฐ Flyweight ๊ณต์œ ๋กœ ์ ˆ์•ฝ Proxy ์ ‘๊ทผ ์ œ์–ด ๐ŸŽญ ํ–‰๋™ ํŒจํ„ด (11๊ฐœ) Chain of Responsibility Command Interpreter Iterator Mediator Memento Observer State Strategy Template Method Visitor ์ด 23๊ฐ€์ง€ ํŒจํ„ด ยท 1994๋…„ GoF ์ •์˜ ยท ํ˜„์žฌ๋„ ์†Œํ”„ํŠธ์›จ์–ด ๊ณตํ•™์˜ ํ•ต์‹ฌ ์ง€์‹
๐ŸŽฏ ๋งˆ๋ฌด๋ฆฌ: ๋””์ž์ธ ํŒจํ„ด์„ ๋Œ€ํ•˜๋Š” ์˜ฌ๋ฐ”๋ฅธ ์ž์„ธ

์—ฌ๊ธฐ๊นŒ์ง€ GoF 23๊ฐ€์ง€ ํŒจํ„ด ์ค‘ ํ•ต์‹ฌ์ ์ธ ๊ฒƒ๋“ค์„ C++๋กœ ๊ตฌํ˜„ํ•ด๋ดค์–ด!
๋งˆ์ง€๋ง‰์œผ๋กœ ๋””์ž์ธ ํŒจํ„ด์„ ๊ณต๋ถ€ํ•˜๋ฉด์„œ ๊ผญ ๊ธฐ์–ตํ•ด์•ผ ํ•  ๊ฒƒ๋“ค ์ •๋ฆฌํ•ด์ค„๊ฒŒ ๐Ÿ˜Š

๐ŸŒŸ ๋””์ž์ธ ํŒจํ„ด ํ•ต์‹ฌ ๋งˆ์ธ๋“œ์…‹

1. ํŒจํ„ด์€ ์–ธ์–ด๊ฐ€ ์•„๋‹ˆ๋ผ ๊ฐœ๋…์ด์•ผ
C++, Java, Python ์–ด๋””์„œ๋“  ๊ฐ™์€ ํŒจํ„ด์„ ๋‹ค๋ฅธ ๋ฐฉ์‹์œผ๋กœ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์–ด. ์–ธ์–ด์— ์ข…์†๋˜์ง€ ๋ง๊ณ  ๊ฐœ๋…์„ ์ดํ•ดํ•ด!

2. ๋ฌธ์ œ๊ฐ€ ๋จผ์ €, ํŒจํ„ด์€ ๋‚˜์ค‘์ด์•ผ
"์ด ํŒจํ„ด ์จ์•ผ์ง€!" ๊ฐ€ ์•„๋‹ˆ๋ผ "์ด ๋ฌธ์ œ๋ฅผ ์–ด๋–ป๊ฒŒ ํ•ด๊ฒฐํ• ๊นŒ?" ์—์„œ ์‹œ์ž‘ํ•ด์•ผ ํ•ด. ํŒจํ„ด์€ ํ•ด๊ฒฐ์ฑ…์ด์ง€ ๋ชฉ์ ์ด ์•„๋‹˜!

3. ํŒจํ„ด๋“ค์€ ์„œ๋กœ ์กฐํ•ฉ๋ผ
์‹ค์ œ ํ”„๋กœ์ ํŠธ์—์„œ๋Š” ์—ฌ๋Ÿฌ ํŒจํ„ด์ด ํ•จ๊ป˜ ์‚ฌ์šฉ๋ผ. Factory + Singleton, Observer + Command ๊ฐ™์€ ์กฐํ•ฉ์ด ํ”ํ•ด!

4. ๋ฆฌํŒฉํ† ๋ง์„ ํ†ตํ•ด ํŒจํ„ด์ด ๋‚˜ํƒ€๋‚˜์•ผ ํ•ด
์ฒ˜์Œ๋ถ€ํ„ฐ ํŒจํ„ด์„ ๊ฐ•์ œ๋กœ ์ ์šฉํ•˜์ง€ ๋ง๊ณ , ์ฝ”๋“œ๊ฐ€ ๋ณต์žกํ•ด์งˆ ๋•Œ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ํŒจํ„ด์œผ๋กœ ๋ฆฌํŒฉํ† ๋งํ•˜๋Š” ๊ฒŒ ๋งž์•„!

5. ํ˜„๋Œ€ C++ ๊ธฐ๋Šฅ์„ ์ ๊ทน ํ™œ์šฉํ•ด
์Šค๋งˆํŠธ ํฌ์ธํ„ฐ, ๋žŒ๋‹ค, ์ด๋™ ์˜๋ฏธ๋ก ์„ ํ™œ์šฉํ•˜๋ฉด ๋” ์•ˆ์ „ํ•˜๊ณ  ๊ฐ„๊ฒฐํ•œ ํŒจํ„ด ๊ตฌํ˜„์ด ๊ฐ€๋Šฅํ•ด!
๐Ÿ’ก ์ถ”์ฒœ ํ•™์Šต ๋ฆฌ์†Œ์Šค

โ€ข ๐Ÿ“š Design Patterns: Elements of Reusable Object-Oriented Software - GoF ์›์„œ (๋ฐ”์ด๋ธ”!)
โ€ข ๐Ÿ“š Head First Design Patterns - ์ž…๋ฌธ์ž์—๊ฒŒ ์ตœ๊ณ ์˜ ์ฑ…
โ€ข ๐Ÿ“š Modern C++ Design - Andrei Alexandrescu (๊ณ ๊ธ‰์ž์šฉ)
โ€ข ๐ŸŒ refactoring.guru - ํŒจํ„ด๋ณ„ ์‹œ๊ฐ์  ์„ค๋ช…๊ณผ ๋‹ค์–‘ํ•œ ์–ธ์–ด ์˜ˆ์ œ
โ€ข ๐Ÿ’ป ์‹ค์ œ ์˜คํ”ˆ์†Œ์Šค ํ”„๋กœ์ ํŠธ ์ฝ”๋“œ ๋ถ„์„ (Qt, Boost, LLVM ๋“ฑ)

๊ทธ๋ฆฌ๊ณ  ์žฌ๋Šฅ๋„ท์—์„œ C++ ์ „๋ฌธ๊ฐ€์—๊ฒŒ 1:1 ์ฝ”๋“œ ๋ฆฌ๋ทฐ๋ฅผ ๋ฐ›์•„๋ณด๋Š” ๊ฒƒ๋„ ์—„์ฒญ ๋„์›€์ด ๋ผ! ์ด๋ก ๋งŒ์œผ๋กœ๋Š” ํ•œ๊ณ„๊ฐ€ ์žˆ๊ฑฐ๋“  ๐Ÿ˜„

๋””์ž์ธ ํŒจํ„ด์€ ์ฒ˜์Œ์—” ์–ด๋ ต๊ฒŒ ๋А๊ปด์ง€์ง€๋งŒ, ํ•˜๋‚˜์”ฉ ์‹ค์ œ ์ฝ”๋“œ์— ์ ์šฉํ•ด๋ณด๋ฉด์„œ ์ตํžˆ๋‹ค ๋ณด๋ฉด
์–ด๋А ์ˆœ๊ฐ„ "์•„, ์ด ์ƒํ™ฉ์—์„œ๋Š” ์ด ํŒจํ„ด์ด๋„ค!" ํ•˜๊ณ  ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ๋– ์˜ค๋ฅด๊ฒŒ ๋ผ.
๊ทธ ์ˆœ๊ฐ„์ด ์˜ค๋ฉด ์ง„์งœ C++ ๊ฐœ๋ฐœ์ž๋กœ ํ•œ ๋‹จ๊ณ„ ์—…๊ทธ๋ ˆ์ด๋“œ๋œ ๊ฑฐ์•ผ! ๐Ÿš€

๊พธ์ค€ํžˆ ์ฝ”๋”ฉํ•˜๊ณ , ๊พธ์ค€ํžˆ ๋ฆฌํŒฉํ† ๋งํ•˜๊ณ , ๊พธ์ค€ํžˆ ์„ฑ์žฅํ•˜์ž! ํ™”์ดํŒ…! ๐Ÿ’ช

๐Ÿ—๏ธ ๐Ÿ”ง ๐ŸŽญ ๐Ÿ’ป ๐Ÿš€ โšก ๐ŸŽฏ ๐ŸŒŸ ๐Ÿ’ก ๐Ÿ†
๋Œ“๊ธ€ ์ž‘์„ฑ

์ด ๊ธ€์— ๋Œ€ํ•œ ์—ฌ๋Ÿฌ๋ถ„์˜ ์ƒ๊ฐ์„ ๋“ค๋ ค์ฃผ์„ธ์š”

๋Œ“๊ธ€ 0
๋Œ“๊ธ€์„ ๋ถˆ๋Ÿฌ์˜ค๋Š” ์ค‘์ž…๋‹ˆ๋‹ค.

์•„์ง ๋Œ“๊ธ€์ด ์—†์Šต๋‹ˆ๋‹ค.