Decorator Design Pattern Example in Java [Tutorial] (original) (raw)

The Decorator design pattern is one of the famous Gang of Four (GOF) structural design patterns, which provides a dynamic way of extending an object's functionality. It's different than the traditional way of adding new functionality into an object using Inheritance, instead, it uses Composition which makes it flexible and allows the addition of new functionalities at the run time, as opposite to Inheritance, which adds new functionality at compile time. Because of this flexibility, Decorator is one of the darling patterns for many Java developers.

Like many other object-oriented design patterns, the decorator design pattern is introduced by the famous Gang of Four design pattern book, almost 2 decades ago. This means it's a time-tested way of adding new functionalities to an object.

In this Java design pattern tutorial, we will learn the Decorator design pattern by using it in a Java example. This is the best way of learning design patterns, followed by you trying it yourself to apply in similar scenarios.

The decorator pattern is one of the popular design patterns along with the Factory method pattern and Singleton Pattern, and you can see its usage even in JDK itself. A couple of classes from the java.io package like BufferedInputStream, LineNumberInputStream are good examples of a Decorator design pattern in Java.

Btw, if you are new to the design pattern world, then I also suggest you check The Java Design Patterns Masterclass which not only covers Decorator patterns but also other GOF patterns. It was also recently been updated to cover Java SE 8 implementation as well.

How to Code Decorator Design Pattern in Java

In order to show you, how to implement a Decorator pattern, let me first explain the requirements. Do we need to create software for calculating the price for a Sandwich, yummy... no? Since the customer can customize a sandwich by asking for extra cheese or extra fillings, you also need to include the cost of those items in the final price of the Sandwich.

Since this customization can vary a lot among different customers and offer from a shop, creating classes for different types of Sandwich with different fillings or extras like BrownBreadSandWithCheese or WhiteBreaSandwitchWithCheeseAndTomato will just clutter the code with lots of endless small classes.

Now this problem looks like a natural fit for applying the Decorator pattern because we have a base object Sandwich, which can be decorated with extra cheese and fillings. By using the Decorator pattern, you can extend the functionality of the Sandwich class at runtime, based upon the customer's request, which is impossible with Inheritance until you have a specific class for every possible customer request.

This is also one of the reasons why Composition is preferred over Inheritance in Object-oriented design and particularly in Java.

Now, let's see our class structure, We have an abstract class Sandwich, with abstract method price() and a concrete implementation class WhiteBreadSandwich, which cost $3.0.

Now, in order to provide extra cheese, which obviously incurs an extra cost, we are going to use the Decorator design pattern. We have a Decorator abstract class, which will act as a base for Decorators called SandwichDecorator, and a concrete implementation of this as CheeseDecorator.

SandwichDecorator extends Sandwich, to be of the same type as the original object, which is getting decorated. This is a critical requirement of the Decorator pattern so that a decorated object can stand in place of the original object like it can be passed when a method expects the original object.

Decorator adds functionality before or after delegating the task to the original object, which means in this example price of a WhilteBreadSandwich with Cheese will be calculated by the first calculating price of WhiteBreadSandwich and then the price of Cheese.

Finally, I have a class called SandwichMaker, which will make a delicious sandwich for you :) I mean it will test the whole program and demonstrate how the Decorator pattern adds new functionality on the fly at runtime.

I have also used BigDecimal to represent money instead of double primitive to follow best practices suggested in Java Programming Masterclass for Software Developers course by Tim BuchalakaUdemy. If you don't know why to read this Java mistake about using double to represent the price

decorator design pattern example in Java

UML diagram of Decorator Pattern

Here is the UML class diagram of the decorator design pattern. You can see that we have a Component interface, which is used to create ConcreteComponents. In our real-world example, Sandwich is a component interface and WhiteBreadSandwich is a concrete component.

Now if we want to add an additional feature to the Component interface, we create another interface called Decorator, which inherits the Component interface, this is very important because it allows you to pass an instance of the Decorator to any method which accepts an instance of the Component interface.

Now you can create an implementation of a decorator, which has both functionalities provided by the original interface and new features provided by the decorator. This way you can add new features to the existing class hierarchy without modifying tried and tested code.

This is another reason programmers say why the composition is better than Inheritance, but if you want to learn more about design principles and patterns, please see SOLID Principles of Object-Oriented Design, one of the best courses for a programmer who wants to write better code.

Anyway, here is the UML diagram of the Decorator pattern which we have talked about:

Real life example of Decorator design pattern in Java

Sample Code of Decorator Design Pattern in Java

Here is a complete Java program to demonstrate how you can implement a decorator pattern in Java. You can use this sample code to add more features and create new classes. If you are using Eclipse IDE, just create a Java project, select that project in the package explorer and copy the code there, it will automatically create the right packages and Java classes.

Sandwich.java import java.math.BigDecimal;

/**

}

WhiteBreadSandWich.java import java.math.BigDecimal;

/**

}

SandWichDecorator.java /**

}

CheeseDecorator.java import java.math.BigDecimal;

/**

}

SandwichMaker.java /**

}

Output: Price of White bread Sandwich is $3.00 Price of White bread Sandwich, Cheese is $3.50

You can see that now the price is easily calculated based upon the toppings and extras you add to the Sandwich.

These design patterns are very useful for writing code that can withstand the test of time and that's why every serious programmer should learn patterns. If you want to learn more about other OOP design patterns like Decorator and their modern implementation in Java then you can take a look at the Design Patterns in Java course by Dmitri Nestruck on Udemy.

6 Things about Decorator Design Pattern You Should Know

Now, we have seen an example of a decorator pattern in Java, we can quickly summarize a few important things which are worth remembering while implementing or applying a decorator pattern or even to answers design pattern questions like When to use a Decorator design pattern in Java.

1. The Decorator must be of the same type of object, which they are decorating. This can be achieved either by implementing the interface of the object or by extending an abstract class of the original class.

2. The decorator pattern is based on Composition, which means it needs an original object to decorate it. This is achieved by creating a constructor on the decorator class that accepts a base type of original object. like in this example constructor of CheeseDecorator accepts Sandwich objects.

3. Decorator class adds new functionality before or after delegating the task to the original object. In this example, the price of the Decorator i.e. cheese is included after calculating the price of the White Bread Sandwich.

4. The decorator pattern is also a good example of the Open-Closed design principle, which is one of the key principles from Uncle Bob's SOLID design principles.

5. Remember, the Decorator design pattern only affects objects at runtime, it doesn't affect the class. You should use the Decorator Pattern when your intent is to add new functionality at runtime (i.e. a customer order, where you only know about order details, one is placed).

6. There is one disadvantage of the Decorator pattern as well, it adds lots of small classes in the code base, remember the overwhelming number of classes in the java.io package. Though, once you know which classes are main classes, and which are decorators, you tend to get a better understanding of the overall structure. UML diagrams certainly help in this case.

That's all on Decorator design pattern in Java and Object-oriented design. I must say, this is one of the must-know design patterns for senior Java developers, it's general purpose and has lots of use cases as well.