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

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

// Concrete Component: Espresso
class Espresso : public Beverage {
public:
    std::string getDescription() const override {
        return "Espresso";
    }

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

// Concrete Component: House Blend
class HouseBlend : public Beverage {
public:
    std::string getDescription() const override {
        return "House Blend Coffee";
    }

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

// Abstract Decorator: Condiment decorator base class, also a beverage
class CondimentDecorator : public Beverage {
protected:
    std::unique_ptr<Beverage> beverage; // Decorated beverage
public:
    explicit CondimentDecorator(std::unique_ptr<Beverage> b)
        : beverage(std::move(b)) {}
};

// Concrete Decorator: Milk
class Milk : public CondimentDecorator {
public:
    explicit Milk(std::unique_ptr<Beverage> b)
        : CondimentDecorator(std::move(b)) {}

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

    double cost() const override {
        return beverage->cost() + 0.10;
    }
};

// Concrete Decorator: Mocha
class Mocha : public CondimentDecorator {
public:
    explicit Mocha(std::unique_ptr<Beverage> b)
        : CondimentDecorator(std::move(b)) {}

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

    double cost() const override {
        return beverage->cost() + 0.20;
    }
};

// Concrete Decorator: Soy
class Soy : public CondimentDecorator {
public:
    explicit Soy(std::unique_ptr<Beverage> b)
        : CondimentDecorator(std::move(b)) {}

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

    double cost() const override {
        return beverage->cost() + 0.15;
    }
};

// Helper function: Print beverage information
void printBeverage(const Beverage& beverage) {
    std::cout << beverage.getDescription() 
              << " $" << beverage.cost() << std::endl;
}

int main() {
    // An espresso
    auto espresso = std::make_unique<Espresso>();
    printBeverage(*espresso);

    // A house blend with double mocha and milk
    auto houseBlend = std::make_unique<HouseBlend>();
    auto drink = std::make_unique<Mocha>(
                    std::make_unique<Mocha>(
                        std::make_unique<Milk>(std::move(houseBlend))
                    )
                 );
    printBeverage(*drink);

    // An espresso with soy and mocha
    auto espresso2 = std::make_unique<Espresso>();
    auto drink2 = std::make_unique<Soy>(
                     std::make_unique<Mocha>(std::move(espresso2))
                  );
    printBeverage(*drink2);

    return 0;
}

results matching ""

    No results matching ""