For Decorator design pattern, GoF clearly states that :
With decorators, responsibilities can be added and removed at run-time simply by attaching and detaching them.
I am trying to build a skeleton code in C++ where I can easily see how this pattern can add responsibilities to an undecorated object.
My question is how can I remove a particular responsibility. Removing the last wrapped responsibility can be done easily. But can I also remove a responsility added in between.
Here is my sample code :
class Icecream { //Component
public :
virtual void addToppings() = 0 ;
virtual Icecream *getUndecorated() = 0 ;
} ;
class PlainIcecream : public Icecream { //Concrete Component
public :
void addToppings() { cout<<"I am just plain icecream, you may add more flavors\n" ; }
Icecream * getUndecorated() {return this ; }
} ;
class Topping : public Icecream { //Decorator
protected :
Icecream *icecream ;
public :
Topping(Icecream *i) : icecream(i) {}
void addToppings() { icecream->addToppings() ; }
} ;
class PeanutToppings : public Topping { //Concrete Component A
public :
PeanutToppings(Icecream *i) : Topping(i) {}
void addToppings() {
Topping::addToppings() ;
cout<<"Adding peanut toppings for great taste\n" ;
}
Icecream * getUndecorated() {return icecream ; }
} ;
class CandyToppings : public Topping { //Concrete Component A
public :
CandyToppings(Icecream *i) : Topping(i) {}
void addToppings() {
Topping::addToppings() ;
cout<<"Adding candy toppings for yummy flavour\n" ;
}
Icecream * getUndecorated() {return icecream ; }
} ;
main() {
Icecream *icecream_with_candy_and_peanuts = new CandyToppings(new PeanutToppings(new PlainIcecream)) ;
icecream_with_candy_and_peanuts->addToppings() ;
cout<<"_________________________________________________\n" ;
Icecream *icecream_with_only_peanuts = icecream_with_candy_and_peanuts->getUndecorated() ;
icecream_with_only_peanuts->addToppings() ;
cout<<"_________________________________________________\n" ;
Icecream *icecream_plain = icecream_with_only_peanuts->getUndecorated() ;
icecream_plain->addToppings() ;
}
Now I want to know if it is possible to have an icecream with only candy topping from icecream_with_candy_and_peanuts
. Please do not consider why do I want to do so. I am just trying to understand the term
detaching responsibilities
as mentioned in GoF.
Removing the last wrapped responsibility can be done easily
There is no need to have a separate getUndecorated
method. This is not a part of the standard Decorator pattern definition.
Now I want to know if it is possible to have an icecream with only candy topping from icecream_with_candy_and_peanuts
Yes you can. There is not much of a difference between attaching or detaching responsibilities when it comes to the decorator pattern. To detach a responsibility, you just need to recreate your component again :
//attaching responsibilities
Icecream *icecream = new new PlainIcecream();
*icecream = new PeanutToppings(icecream);//wrap around with new respnsibility
*icecream = new CandyToppings(icecream);//wrap around with new responsiblity
//detaching responsibilities
*icecream = new CandyToppings(new PlainIcecream());
Notice how I am using *icecream
in both the cases. You are able to attach and detach responsibilities by confining to a single interface (i.e IceCream
). That's the idea behind the Decorator pattern.
That said, the Composite pattern implemented using a HashMap
(where key is the topping name) would be a better choice in a scenario where you want to be able to arbitrarily add or remove responsibilities from an existing instance.
Bonus tips : The decorator in the Decorator pattern should ideally not be instantiable (Toppings
in your case). It would also help to rename Toppings
to ToppingsDecorator
instead. (I understand this is not the direct question you are asking. This is purely for the benefit of other readers)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With