Decorator pattern adds behavior to objects without affecting other objects of the same class. The decorator pattern is a useful alternative to creating sub-classes.
Create a module for each decorator. This approach is more flexible than inheritance because you can mix and match responsibilities in more combinations. Additionally, because the transparency allows decorators to be nested recursively, it allows for an unlimited number of responsibilities.
Assume the Pizza class has a cost method that returns 300:
class Pizza def cost 300 end end
Represent pizza with an added layer of cheese burst and the cost goes up by 50. The simplest approach is to create a
PizzaWithCheese subclass that returns 350 in the cost method.
class PizzaWithCheese < Pizza def cost 350 end end
Next, we need to represent a large pizza that adds 100 to the cost of a normal pizza. We can represent this using a LargePizza subclass of Pizza.
class LargePizza < Pizza def cost 400 end end
We could also have an ExtraLargePizza which adds a further cost of 15 to our LargePizza. If we were to consider that these pizza types could be served with cheese, we would need to add LargePizzaWithChese and ExtraLargePizzaWithCheese subclasses.we end up with a total of 6 classes.
To simplify the approach, use modules to dynamically add behavior to Pizza class:
Module + extend + super decorator:->
class Pizza def cost 300 end end module CheesePizza def cost super + 50 end end module LargePizza def cost super + 100 end end pizza = Pizza.new #=> cost = 300 pizza.extend(CheesePizza) #=> cost = 350 pizza.extend(LargePizza) #=> cost = 450 pizza.cost #=> cost = 450