Decorator Pattern

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.
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
@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
I don't think AddOnDecorator should derive from Beverage. Sugar is a decorator but it definitely isn't a beverage.
call it Sugared_drink then
Last edited on
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
Topic archived. No new replies allowed.