Search code examples
c++classpolymorphismumlabstract-class

how to implement adding a price to an object without modifying the uml diagram c++


I don't know how to implement adding a price to a menu so I don't change the uml chart.

Description of the requirements:

Abstract class Menu has a purely virtual method description().
Withlemon and Withcoffee contains a menu and method description() that adds text “With lemon”, respectively “with coffee”, in the description of the menu contained.
The price of a menu which contains lemon increases by 4, the one with coffee costs an additional 5.
The Breakfast class is a menu without lemon and without coffee, the method description() returns the name of the menu.
In the pizzeria restaurant there are 2 small dishes breakfast: Eggs and Omelet, at the price of 10 respectively 15.

Create only methods and attributes that result from the UML diagram (just add specific things C ++ ex: constructors).

Here the UML diagram:
enter image description here

Here my code:

#include <iostream>
using namespace std;

class Menu {
private:
    int price = 0;
public:
    virtual string description() = 0;
    int getPrice() {
        return price;
    }
    

};
class WithLemon : public Menu {
private:
    Menu* meniu;
    
public:
    WithLemon() = default;
    WithLemon(Menu* n) :
        meniu{ n } {}
    string description() {
        return meniu->description() + " with lemon ";
    }
};

class WithCoffee : public Menu {
private:
    Menu* meniu;
public:
    WithCoffee(Menu* n) :
        meniu{ n } {
    }
    string description() {
        return meniu->description() + " with coffee ";
    }
};

class Breakfast : public Menu {
private:
      string name;
public:
    Breakfast(string n) :
        name{ n } {
    }
    string description() {
        return name;
    }
};

int main() {
    Breakfast a{"eggs"};
    WithCoffee transformer1{ &a };
    transformer1 = &a;
    cout << transformer1.description() << " " << transformer1.getPrice() << endl;
    return 0;
}

Solution

  • Problems with the diagram

    First, the diagram doesn't correspond to the narrative:

    • There is already a price and a getPrice(). You can therefore do exactly as with description(): just provide your own implementation.
    • Then, it doesn't show that description is purely virtual in Menu: the operation should have been shown in italic.
    • In addition, since that WithLemon, WithCoffee and Breakfast provide their own concrete implementation of description(), it should have been shown in these classes as well.

    Hint: WithLemon and WithCoffee are decorators of Menu.

    Problems with the code

    In the base class Menu, since you have one virtual function, it's a good practice to give it a virtual destructor. Since you have a price and there's no way to change it afterwards, it should be included in the constructor:

    class Menu {
    private:
        int price;
    public:
        Menu(int p=0) :  price{p} {} 
        ...
        virtual ~Menu() {}
    };
    

    Now you should also provide for the price, in Breakfast, again at construction. A small advice: whenever you override a virtual function from a base class, use the keyword override; it will save you hours of debugging of nastry errors in the future :

    class Breakfast : public Menu {
    private:
          string name;
    public:
        Breakfast(string n, int p) :
            name{ n }, Menu{ p}  {
        }
        string description() override {
            return name;
        }
    };
    

    You have well implemented the decorators. I'd just recommend to add the override keywords for the same reasons.

    Finally, to meet all the requirements, without contradicting the class-diagram, you may make getPrice() virtual: it's not a pure virtual function, since you provide a default implementation in the base Menu. In the decorator, you'd just override the method with a more specialized one:

    class WithCoffee : public Menu {
    private:
        Menu* meniu;
    public:
        WithCoffee(Menu* n) :
            meniu{ n } {
        }
        string description() override{
            return meniu->description() + " with coffee ";
        }
        int getPrice() override{
            return meniu->getPrice()+5; 
        }
    };
    

    In my view, such overriding should be shown in the diagram. But since your teacher didn't show the overriding of an abstract method (which is far more important), he/she cannot complain that in your code override a method where a default implementation is provided.

    Finally, you can test this:

    Breakfast a{"eggs", 10};
    WithCoffee breakfast_with_coffee { &a };
    cout << breakfast_with_coffee.description() << " " << breakfast_with_coffee.getPrice() << endl;
    

    Here the online demo.

    Important remark: this is of course for learning purpose only. In real world, you'd have methods to change the price. Moreover, decroators wouldn't just add hard-coded texts and amounts. Finally, you'd probably use smart pointers, instead of the error-prone raw pointers.