"cafeMocha = Espresso(SteamedMilk(Chocolate(
Whipped(Decaf(Mug())))))"
One of the GoF's examples for this pattern was a way to put a border on a graphical component. Interestingly, Java's Swing team chose a different solution for that exact problem. This suggests an alternative pattern to the Decorator pattern, which I'll call the "Extras" pattern.
In this pattern, the object being decorated has a separate field for extras:
class Mug:
def __init__(self, drink, extras):
self.drink = drink
self.extras = extras
def getTotalCost(self):
total = self.drink.getCost()
for e in self.extras:
total += e.getCost()
return total
def getDescription(self):
d = self.drink.getDescription()
for e in self.extras:
d += ' ' + e.getDescription()
return d
myDrink = Mug(Espresso(), [SteamedMilk(), Chocolate(),
Whipped(), Decaf()])
One advantage here is improved mutability. If the customer actually wanted Raspberry flavoring instead of Chocolate, you just do:
myDrink.extras[1] = Raspberry()
As a pleasant side effect, Mug now acts as a container class. :-)
A general design principle for using Python is: prefer the flat to the recursive. A corollary is: prefer Python lists to linked lists.