Decorator Pattern in C++

C decorator design pattern (using the pizza example)

not sure why the post was down voted but anyway... A friend solved the problem for me and I thought I'd post the answer here - thank you Marcel :o)

#include <stdio.h>
#include <stdlib.h>

typedef struct _pizza pizza_t;
typedef double (* getCost)(struct _pizza * self);

typedef struct _pizza {
getCost getCostFunc;
} pizza_t;

typedef struct _plainPizza {
pizza_t base;
} plainPizza_t;

typedef struct _toppingDecorator {
pizza_t base;
pizza_t * decorate;
} toppingDecorator_t;

// these are the pizzas
double plainPizzaCost (plainPizza_t self) {
return 5;
}

// these are the toppings
double mozzarellaCost (toppingDecorator_t * self) {
return self->decorate->getCostFunc(self->decorate) + 3;
}
double tomatoCost (toppingDecorator_t * self) {
return self->decorate->getCostFunc(self->decorate) + 2;
}
double salamiCost (toppingDecorator_t * self) {
return self->decorate->getCostFunc(self->decorate) + 1;
}

int main(int argc, const char * argv[]) {

plainPizza_t plainPizza;
plainPizza.base.getCostFunc = (getCost) plainPizzaCost;

toppingDecorator_t mozzarella;
mozzarella.base.getCostFunc = (getCost) mozzarellaCost;
mozzarella.decorate = (pizza_t *) &plainPizza;

toppingDecorator_t tomato;
tomato.base.getCostFunc = (getCost) tomatoCost;
tomato.decorate = (pizza_t *) &mozzarella;

toppingDecorator_t salami;
salami.base.getCostFunc = (getCost) salamiCost;
salami.decorate = (pizza_t *) &tomato;

printf ("A tomato pizza costs %f\n", tomato.base.getCostFunc((pizza_t *) &tomato));
printf ("A salami pizza costs %f\n", salami.base.getCostFunc((pizza_t *) &salami));
}

Decorator pattern on the real example in C++

In main function you should do this:

Burger* b = new Cheese(new ConcretteBurger);

Instead of this:

Burger* b = new ConcretteBurger(new Cheese);

The cheese decorates the burger, not the opposite. More in general, the decorator class takes a reference to the decorated class and not the opposite.

Note also that the constructor of BurgerDecorator has a bug. It should be:

BurgerDecorator(Burger* bb){
b = bb;
}

Or even better:

BurgerDecorator(Burger* bb): b{bb} {}

Instead of bb = b; as it is in your example.

Finally, add a virtual destructor to your base class to avoid leaks:

class Burger{
public:
virtual ~Burger() = default;
virtual int get_cost() = 0;
};

See your code once fixed on wandbox.

Decorator Design Pattern in C++

While you could definitely eliminate the more abstract Decorator class in favour of inlining its members into the more concrete decorators, there are at least two benefits I can see to retaining it:

  1. If you so desired, you could restrict methods to accept or return decorated objects; for example, MilkShake *undecorate(MilkShakeDecorator *) is type-safe, but how would you do this without the intermediate type? While this might feel inane, consider that in a real world application, your types are not milkshakes, but potentially things like networking protocols. Being able to take a stack of protocols and slip one off could be quite a useful application.

  2. It fosters a better understanding of what's going on. If I simply had class MangoMilkShake : MilkShake, my thought may be that it's going to implement its behaviours on its own, i.e. may be fixed to a particular base flavour. By instead seeing that is a decorator, it gives me a better understanding of how the type may behave, i.e. it will adapt some other type to provide addition behaviours.

As with all opinion questions, you should take my answer with a grain of salt, as there can be arguments for both sides.

Understanding Decorator Design Pattern in C#

It should be a comment, but I have too many words.

For example, you have an object and interface, like Repository : IRepository.

public interface IRepository
{
void SaveStuff();
}

public class Repository : IRepository
{
public void SaveStuff()
{
// save stuff
}
}

and client, which probably was written by someone else

class RepoClient
{
public void DoSomething(IRepository repo)
{
//...
repo.SaveStuff();
}
}

And once you decided, that ALL calls to repository should be logged. But you have a problem: the Repository class is from an external library and you don't want to change that code. So you need to extend the Repository's behavior that you use. You write RepositoryLogDecorator : IRepository, and inside on each method do the logging, like

public class RepositoryLogDecorator  : IRepository
{
public IRepository _inner;

public RepositoryLogDecorator(IRepository inner)
{
_inner = inner;
}

public void SaveStuff()
{
// log enter to method
try
{
_inner.SaveStuff();
}
catch(Exception ex)
{
// log exception
}
// log exit to method
}
}

So, before you could use client as

var client = new RepoClient();
client.DoSomething(new Repository());

but now you can use

var client = new RepoClient();
client.DoSomething(new RepositoryLogDecorator(new Repository()));

Note, that this is a very simple example. In real projects, where object created primary with DI container, you will be able to use decorator by changing some config.

So, decorator is used to extend functionality of object without changing object or client.

Another benefit of decorator: your decorator does not depend on Repository implementation. Only depends from an interface IRepository. Why this is an advantage? If somehow you decide to write you own implementation of IRepository

public class MyAwesomeRepository : IRepository
{
public void SaveStuff()
{
// save stuff, but AWESOME!
}
}

you will be able to automatically decorate this with decorator, which already exist

var client = new RepoClient();
client.DoSomethig(new RepositoryLogDecorator(new MyAwesomeRepository()));

Want to see example from real software? (just as sample, code is ugly, I know) => go here

Decorator pattern in C++

Vince Huston Design Patterns, even though its layout is poor, has C++ implementation for most design patterns in the Gang of Four book.

Click for Decorator.

There isn't much difference with Java, except the manual memory handling that you'd better wrap with smart pointers :)

Should we use decorator pattern in C++?

With the decorator pattern you can decorate objects at run-time, while multiple inheritance is a compile-time solution. This allows you to freely combine different decorators with minimal overhead, whereas with multiple inheritance, you need a new class for each combination of decorators.

Also, multiple inheritance is hard to get right if you are inheriting anything but interface-classes (classes that only have pure virtual methods).

Decorator Pattern in C++ with templates

why is the partial specialization?

The intent is to provide a function type, but also get out of it return type and types of the arguments.

You can do that only with a partial specialization, that is the following one:

template<typename> struct S;

template<typename R, typename... Args>
struct S<R(Args...)> { /* ... */ };

As you can see, the primary template doesn't have a definition, for it's not required at all in this case.

Anyway, note that it accepts only one type. The intent is to use it as it follows: S<void(int, char)>.

How could you know that the return type is void and int and char are your parameters in the primary template? You cannot, but you do within the specialization.

is it possible to modify the code so it can take a lambda as well?

You can even get rid of std::functions and function pointers, so as to have a lambda-only based solution. Using lambdas you can easily capture or invoke the other functions.

Here is a minimal, working example:

#include <iostream>
#include<type_traits>
#include <utility>

template <typename F>
struct Logger: F
{
std::string name_;

Logger(F &&func, const std::string& name):
F{std::move(func)}, name_{name} {}

template<typename... Args>
auto operator() (Args&&... args)
{
std::cout << "Entering " << name_ << std::endl;
auto result = F::operator()(std::forward<Args>(args)...);
std::cout << "Exiting " << name_ << std::endl;
return result;
}
};

template <typename F>
auto make_logger(F &&f, const std::string& name)
{
return Logger<std::decay_t<F>>{std::move(f), name};
}

double add(double a, double b, double c)
{
std::cout << a << " + " << b << " + " << c << " = " << a + b + c << std::endl;
return a + b + c;
}

int main()
{
auto logged_add = make_logger([](auto... args) { return add(args...); }, "Add");
auto result = logged_add(2,3,5);
}

Signature-preserving Decorator Pattern in C++?

Since in C++ overloading operator typeid is not allowed - the only solution which I can propose is to add virtual method returning type_info for decorated type:

class Component {
public:
Component();
virtual void doSomething();
virtual const std::type_info& decorated_type() const
{ return typeid(*this); }
};

class Decorator : public Component {
public:
Decorator(Component*);
virtual void doSomething();
virtual const std::type_info& decorated_type() const
{ return typeid(*_component); }
private:
Component* _component;
};

Maybe better version for Decorator::decorated_type() const:

virtual const std::type_info& decorated_type() const 
{ return _component->decorated_type(); }

GoF decorator pattern using static polymorphism (templates) in c++

Basically, the abstract interface from the polymorphic decorator becomes an implicitly defined concept and you nest the types. For example:

struct BasicCoffee
{
void print() {std::cout << "Coffee!\n";}
};

template <class T>
struct CreamDecorator
{
CreamDecorator(T x) : mNested(x) {}

void print() {mNested.print(); std::cout << "..with cream!\n";}
T mNested;
};

template <class T>
struct SugarDecorator
{
SugarDecorator(T x) : mNested(x) {}

void print() {mNested.print(); std::cout << "..with sugar!\n";}
T mNested;
};

You probably want to use the object generator idiom to make composition easier:

template <class T>
CreamDecorator<T> addCream(T x) {return CreamDecorator<T>(x);}

template <class T>
SugarDecorator<T> addSugar(T x) {return SugarDecorator<T>(x);}

Since you don't have a common type to store decorated objects, you need to use some kind of type inference. For example:

auto myCoffee = addSugar(addCream(BasicCoffee()));
myCoffee.print();

Alternatively, use the value you get from the object generators as an rvalue (This can be useful if you are stuck with C++03 - type erasure can also help!):

addSugar(addCream(BasicCoffee())).print();


Related Topics



Leave a reply



Submit