cpp

examples

examples.cpp⚙️
/**
 * Design Patterns - Examples
 * Compile: g++ -std=c++17 -Wall examples.cpp -o examples
 */

#include <iostream>
#include <string>
#include <vector>
#include <memory>
#include <functional>
using namespace std;

// ============================================================
// SECTION 1: SINGLETON PATTERN
// ============================================================

class Logger {
    static Logger* instance;
    vector<string> logs;
    Logger() = default;
    
public:
    Logger(const Logger&) = delete;
    Logger& operator=(const Logger&) = delete;
    
    static Logger& getInstance() {
        static Logger instance;
        return instance;
    }
    
    void log(const string& msg) {
        logs.push_back(msg);
        cout << "  [LOG] " << msg << endl;
    }
    
    void showAll() {
        cout << "  All logs (" << logs.size() << "):" << endl;
        for (const auto& l : logs) cout << "    - " << l << endl;
    }
};

void demoSingleton() {
    cout << "--- Singleton Pattern ---" << endl;
    
    Logger::getInstance().log("First message");
    Logger::getInstance().log("Second message");
    
    // Same instance
    auto& logger = Logger::getInstance();
    logger.log("Third message");
    logger.showAll();
}

// ============================================================
// SECTION 2: FACTORY PATTERN
// ============================================================

class Shape {
public:
    virtual void draw() const = 0;
    virtual ~Shape() = default;
};

class Circle : public Shape {
public:
    void draw() const override { cout << "    Drawing Circle" << endl; }
};

class Rectangle : public Shape {
public:
    void draw() const override { cout << "    Drawing Rectangle" << endl; }
};

class Triangle : public Shape {
public:
    void draw() const override { cout << "    Drawing Triangle" << endl; }
};

class ShapeFactory {
public:
    static unique_ptr<Shape> create(const string& type) {
        if (type == "circle") return make_unique<Circle>();
        if (type == "rectangle") return make_unique<Rectangle>();
        if (type == "triangle") return make_unique<Triangle>();
        return nullptr;
    }
};

void demoFactory() {
    cout << "\n--- Factory Pattern ---" << endl;
    
    auto shapes = {"circle", "rectangle", "triangle"};
    for (const auto& s : shapes) {
        auto shape = ShapeFactory::create(s);
        if (shape) shape->draw();
    }
}

// ============================================================
// SECTION 3: BUILDER PATTERN
// ============================================================

class Pizza {
public:
    string dough, sauce, topping;
    
    void show() const {
        cout << "    Pizza: " << dough << " dough, "
             << sauce << " sauce, " << topping << " topping" << endl;
    }
};

class PizzaBuilder {
protected:
    Pizza pizza;
public:
    virtual PizzaBuilder& setDough() = 0;
    virtual PizzaBuilder& setSauce() = 0;
    virtual PizzaBuilder& setTopping() = 0;
    Pizza build() { return pizza; }
    virtual ~PizzaBuilder() = default;
};

class MargheritaBuilder : public PizzaBuilder {
public:
    PizzaBuilder& setDough() override { pizza.dough = "thin"; return *this; }
    PizzaBuilder& setSauce() override { pizza.sauce = "tomato"; return *this; }
    PizzaBuilder& setTopping() override { pizza.topping = "mozzarella"; return *this; }
};

class PepperoniBuilder : public PizzaBuilder {
public:
    PizzaBuilder& setDough() override { pizza.dough = "thick"; return *this; }
    PizzaBuilder& setSauce() override { pizza.sauce = "spicy"; return *this; }
    PizzaBuilder& setTopping() override { pizza.topping = "pepperoni"; return *this; }
};

void demoBuilder() {
    cout << "\n--- Builder Pattern ---" << endl;
    
    MargheritaBuilder mb;
    Pizza margherita = mb.setDough().setSauce().setTopping().build();
    margherita.show();
    
    PepperoniBuilder pb;
    Pizza pepperoni = pb.setDough().setSauce().setTopping().build();
    pepperoni.show();
}

// ============================================================
// SECTION 4: OBSERVER PATTERN
// ============================================================

class IObserver {
public:
    virtual void update(float temp) = 0;
    virtual ~IObserver() = default;
};

class WeatherStation {
    vector<IObserver*> observers;
    float temperature = 0;
    
public:
    void addObserver(IObserver* o) { observers.push_back(o); }
    
    void setTemperature(float temp) {
        temperature = temp;
        notify();
    }
    
    void notify() {
        for (auto* o : observers) o->update(temperature);
    }
};

class PhoneDisplay : public IObserver {
    string name;
public:
    PhoneDisplay(const string& n) : name(n) {}
    void update(float temp) override {
        cout << "    " << name << " shows: " << temp << "°C" << endl;
    }
};

void demoObserver() {
    cout << "\n--- Observer Pattern ---" << endl;
    
    WeatherStation station;
    PhoneDisplay phone1("Phone1"), phone2("Phone2");
    
    station.addObserver(&phone1);
    station.addObserver(&phone2);
    
    cout << "  Temperature changes to 25°C:" << endl;
    station.setTemperature(25);
    
    cout << "  Temperature changes to 30°C:" << endl;
    station.setTemperature(30);
}

// ============================================================
// SECTION 5: STRATEGY PATTERN
// ============================================================

class SortStrategy {
public:
    virtual void sort(vector<int>& data) = 0;
    virtual ~SortStrategy() = default;
};

class BubbleSort : public SortStrategy {
public:
    void sort(vector<int>& data) override {
        cout << "    Using Bubble Sort" << endl;
        // Simple bubble sort
        for (size_t i = 0; i < data.size(); i++)
            for (size_t j = 0; j < data.size() - 1; j++)
                if (data[j] > data[j+1]) swap(data[j], data[j+1]);
    }
};

class QuickSortStrategy : public SortStrategy {
public:
    void sort(vector<int>& data) override {
        cout << "    Using Quick Sort (std::sort)" << endl;
        std::sort(data.begin(), data.end());
    }
};

class Sorter {
    unique_ptr<SortStrategy> strategy;
public:
    void setStrategy(unique_ptr<SortStrategy> s) { strategy = move(s); }
    void sort(vector<int>& data) { strategy->sort(data); }
};

void demoStrategy() {
    cout << "\n--- Strategy Pattern ---" << endl;
    
    vector<int> data1 = {5, 2, 8, 1, 9};
    vector<int> data2 = {5, 2, 8, 1, 9};
    
    Sorter sorter;
    
    sorter.setStrategy(make_unique<BubbleSort>());
    sorter.sort(data1);
    
    sorter.setStrategy(make_unique<QuickSortStrategy>());
    sorter.sort(data2);
}

// ============================================================
// SECTION 6: DECORATOR PATTERN
// ============================================================

class Coffee {
public:
    virtual string getDescription() const = 0;
    virtual double getCost() const = 0;
    virtual ~Coffee() = default;
};

class SimpleCoffee : public Coffee {
public:
    string getDescription() const override { return "Coffee"; }
    double getCost() const override { return 2.0; }
};

class CoffeeDecorator : public Coffee {
protected:
    unique_ptr<Coffee> coffee;
public:
    CoffeeDecorator(unique_ptr<Coffee> c) : coffee(move(c)) {}
};

class MilkDecorator : public CoffeeDecorator {
public:
    using CoffeeDecorator::CoffeeDecorator;
    string getDescription() const override {
        return coffee->getDescription() + " + Milk";
    }
    double getCost() const override { return coffee->getCost() + 0.5; }
};

class SugarDecorator : public CoffeeDecorator {
public:
    using CoffeeDecorator::CoffeeDecorator;
    string getDescription() const override {
        return coffee->getDescription() + " + Sugar";
    }
    double getCost() const override { return coffee->getCost() + 0.2; }
};

void demoDecorator() {
    cout << "\n--- Decorator Pattern ---" << endl;
    
    auto coffee = make_unique<SimpleCoffee>();
    cout << "    " << coffee->getDescription() << ": $" << coffee->getCost() << endl;
    
    auto withMilk = make_unique<MilkDecorator>(move(coffee));
    cout << "    " << withMilk->getDescription() << ": $" << withMilk->getCost() << endl;
    
    auto withSugar = make_unique<SugarDecorator>(move(withMilk));
    cout << "    " << withSugar->getDescription() << ": $" << withSugar->getCost() << endl;
}

// ============================================================
// SECTION 7: COMMAND PATTERN
// ============================================================

class Command {
public:
    virtual void execute() = 0;
    virtual void undo() = 0;
    virtual ~Command() = default;
};

class Light {
public:
    void on() { cout << "    Light ON" << endl; }
    void off() { cout << "    Light OFF" << endl; }
};

class LightOnCommand : public Command {
    Light& light;
public:
    LightOnCommand(Light& l) : light(l) {}
    void execute() override { light.on(); }
    void undo() override { light.off(); }
};

class LightOffCommand : public Command {
    Light& light;
public:
    LightOffCommand(Light& l) : light(l) {}
    void execute() override { light.off(); }
    void undo() override { light.on(); }
};

class RemoteControl {
    vector<unique_ptr<Command>> history;
public:
    void executeCommand(unique_ptr<Command> cmd) {
        cmd->execute();
        history.push_back(move(cmd));
    }
    void undoLast() {
        if (!history.empty()) {
            history.back()->undo();
            history.pop_back();
        }
    }
};

void demoCommand() {
    cout << "\n--- Command Pattern ---" << endl;
    
    Light light;
    RemoteControl remote;
    
    remote.executeCommand(make_unique<LightOnCommand>(light));
    remote.executeCommand(make_unique<LightOffCommand>(light));
    
    cout << "  Undo:" << endl;
    remote.undoLast();
}

// ============================================================
// MAIN
// ============================================================

int main() {
    cout << "╔══════════════════════════════════════╗" << endl;
    cout << "║      DESIGN PATTERNS - EXAMPLES      ║" << endl;
    cout << "╚══════════════════════════════════════╝" << endl;
    
    demoSingleton();
    demoFactory();
    demoBuilder();
    demoObserver();
    demoStrategy();
    demoDecorator();
    demoCommand();
    
    cout << "\n=== Complete ===" << endl;
    return 0;
}
Examples - C++ Tutorial | DeepML