Decorator Pattern
Imagine there is an object where if we send a message Speak () to the object returns “Hello World” as response. Decorator pattern says that if I want to change the behavior of the object, I can do so without changing the contents of the object at run time. Decorator pattern wraps the object in another object, so when we send a message Speak () to the outer object it sends the message to the inner object which computes and sends the value to the outer object then the outer object returns the value back to client. This process of wrapping can be done indefinitely.
The object in the middle is called component and the object which wraps the component is called decorator. These decorators behave like component from outside. A decorator pattern is a component and has a component. Decorator pattern attaches addition responsibilities to an object dynamically. Decorators provide flexible alternative to subclassing for extending functionality. A decorator pattern adds additional behavior to a component at run time.
Example
Let’s consider an example where we have a Beverage abstract class with methods GetDescription and Cost. We have Decaf and Espresso inheriting from Beverage class implementing Cost method. GetDescription method in base class is reused by these sub classes. Now consider we have extras apart from simple Decaf like skimmed milk, whipped cream etc. If we have classes for each one of these extras it will result in class explosion. Another way of handling this is having Boolean methods which indicates these extras but having these many conditionals is unmanageable and it violates the open closed principle. Decorator pattern helps to address this problem.
Instead of introducing multiple classes which represents all these combinations such as Espresso with Mocha, Espresso with chocolate. We can introduce an AddOnDecorator which implements the method GetDescription. Since the decorator is a component and has a component the AddOnDecorator is of type Beverage and has a Beverage. The AddOnDecorator is inherited by Caramel Decorator and Soy Decorator sub classes which generates multiple combinations. With this design we can create Espresso with Caramel, Espresso with Soy and other possible combinations. The cost method implementation in these decorators will be essentially adding the existing cost of the beverage plus the cost of that decorator. A decorator refers to thing its wrapping. A component can have multiple decorators wrapped around it.
UML Diagram
We have a component base class having MethodA() and MethodB() and a concrete component derived class inheriting from the component class. Similarly we have Decorator class which inherits from component, so it behaves as a component and also has a reference to a concrete component. Concrete Decorator1 and Concrete Decorator2 classes inherit from the Decorator base class.
Code
We have an Abstract class Beverage which acts as a component and Espresso concrete component inheriting the Beverage. Abstract class AddOnDecorator is of type component, in this case it is of type Beverage and concrete decorator Caramel Decorator inheriting the AddOnDecorator. By proxy Caramel Decorator is of type Beverage since it inherits AddOnDecorator which is of type Beverage. CaramelDecorator also has a reference to the Beverage since a decorator wraps the component or another decorator.
GitHub: Decorator Pattern
#14DayOf100DaysOfCode
Comments