Decorator Pattern

Jul 13, 2020 at 7:35am
I've implemented a decorator pattern example, but I'm unsure if I have it done correctly. I'm unsure if the destructors are implemented in the right manner. Especially I'm unsure whether it's sufficient implementing the dtor only once in the superclass if the derived classes do not add further members or methods.

Also, I ask me whether there exists away, getting rid of the pointers.

I would be pleased if someone could check the code below.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
#include <iostream>
#include <string>
#include <cstdlib>

class Beverage
{
    public:
        virtual ~Beverage() {}
        virtual std::string name() const = 0;
        virtual int cost() const = 0;
};

class AddonDecorator : public Beverage
{
    public:
        AddonDecorator( Beverage * beverage )
         : m_beverage{ beverage }
        {}
        ~AddonDecorator() { delete m_beverage; }

        virtual std::string name() const override = 0;
        virtual int cost() const override = 0;

    protected:
        Beverage * m_beverage;
};


class Coffee : public Beverage
{
    public:
        std::string name() const override { return "coffee"; }
        int cost() const override { return 40; }
};

class Tea : public Beverage
{
    public:
        std::string name() const override { return "tea"; }
        int cost() const override { return 10; }
};


class Milk : public AddonDecorator
{
    public:
        Milk( Beverage * beverage ) : AddonDecorator( beverage ) {}
        std::string name() const override { return m_beverage->name() + ", milk"; }
        int cost() const override { return m_beverage->cost() + 5; }
};

class Sugar : public AddonDecorator
{
    public:
        Sugar( Beverage * beverage ) : AddonDecorator( beverage ) {}
        std::string name() const override { return m_beverage->name() + ", sugar"; }
        int cost() const override { return m_beverage->cost() + 1; }
};

int main()
{
    std::string input;
    Beverage * beverage = nullptr;

    std::cout << "tea = 1, coffee = 2. Make your choice: ";
    std::getline(std::cin, input);
    switch( std::stoi(input) )
    {
        case 1: beverage = new Tea; break;
        case 2: beverage = new Coffee; break;
        default: std::exit( EXIT_SUCCESS );
    }

    for( int i = 0; i < 3; ++ i )
    {
        std::cout << "Do you want some add some addons (y/n)?\n";
        std::getline( std::cin, input );
        if( input[0] != 'y' && input[0] != 'Y' )
            break;

        std::cout << "milk = 1, sugar = 2\n";
        std::getline( std::cin, input );
        switch( std::stoi(input) )
        {
            case 1: beverage = new Milk( beverage ); break;
            case 2: beverage = new Sugar( beverage ); break;
            default: std::exit( EXIT_SUCCESS );
        }
    }

    std::cout << "You chosed " << beverage->name() << ".\n"
              << "Enter " << beverage->cost() << " cent into the slot.\n";

    delete beverage;
}

Thanks for looking over my code.
Jul 13, 2020 at 9:06am
The destructor on line 19 is wrong. This way you will delete the same object created on line 69/70 more than once. Consider to use a smart pointer. In this case a shared_ptr.

Also, I ask me whether there exists away, getting rid of the pointers.
The pointer is actually kind of the point of the Decorator Pattern. To get rid of the pointer you need another structure.

It is questionable whether AddonDecorator is-a Beverage or the Beverage has-a AddonDecorator. See:

https://www.w3resource.com/java-tutorial/inheritance-composition-relationship.php
Jul 13, 2020 at 11:41pm
@coder777: see lines 85, 86
it's like doing push_front on a linked list where if you kill the head the rest dies
so every node is responsible of the lifetime of its `next' neighbour, the behaviour is the one of unique_ptr
(so the destructor on line 19 is needed)

@OP: not a fan of stateless classes, perhaps would have used composite
Jul 15, 2020 at 3:03pm
I don't think AddOnDecorator should derive from Beverage. Sugar is a decorator but it definitely isn't a beverage.
Jul 15, 2020 at 5:13pm
call it Sugared_drink then
Last edited on Jul 15, 2020 at 5:13pm
Jul 16, 2020 at 11:17am
dhayden wrote:
I don't think AddOnDecorator should derive from Beverage. Sugar is a decorator but it definitely isn't a beverage.

I consider it more as a technical relationship than a logical one. It's somewhat of the fashion of question whether an ellipse should derive from a circle shape.
Last edited on Jul 16, 2020 at 11:19am
Topic archived. No new replies allowed.