Decorator Design Pattern in Java with Example

The Decorator design Pattern is one of the famous Gang of Four (GOF) structural design pattern, 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 to add 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 developer. Btw, like many others 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 into 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 pattern, followed you try 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 it's usage even in JDK itself. A couple of classes from the java.io package like BufferedInputStream, LineNumberInputStream are a good example of Decorator design pattern in Java. 

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




Decorator Design Pattern in Java

In order to show you, how to implement a Decorator pattern, let me first explain 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 extra cheese or extra fillings, you also need to include the cost of those items in the final price of 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 a natural fit for applying 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 Sandwich class at runtime, based upon 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 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 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 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 Effective Java. If you don't know why to read this Java mistake about using double to represent the price






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 inherit Component interface, this is very important because it allows you to pass an instance of 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 feature provided by the decorator. This way you can add new features in 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 course 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 right packages and Java classes. 


Sandwich.java
import java.math.BigDecimal;

/**
 * Base class for all types of Sandwich, cost method is abstract because
 * different sandwiches has different price.
 *
 * @author Javin Paul
 */
public abstract class Sandwich {   
    protected String description = "Sandwich";  
   
    public String getDescription(){
        return description;
    }
   
    public abstract BigDecimal price();
}


WhiteBreadSandWich.java
import java.math.BigDecimal;

/**
 * A Concrete implementation of abstract Sandwich class, which represent a WhiteBread
 * Sandwich, whose price is 3.0$.
 *
 * @author Javin Paul
 */
public class WhiteBreadSandWich extends Sandwich {
   
    public WhiteBreadSandWich(String desc){
       description = desc;
    }
   
    @Override
    public BigDecimal price() {
        return new BigDecimal("3.0");
    }
   
}

SandWichDecorator.java
/**
 * Base class for Decorators, this class inherit from Sandwich, so that
 * it can be of same type, which is required to pass decorators where
 * original object is expected. Later, this class will also come handy
 * to provide common functionalities to Decorators.
 *
 * @author
 */
public abstract class SandWichDecorator extends Sandwich {  
   
    @Override
    public abstract BigDecimal price();
   
}

CheeseDecorator.java
import java.math.BigDecimal;

/**
 * A Decorator class, which adds cheese (new functionality) into Sandwich object.
 * This Decorator class modifies price() and getDescritption() method to implement
 * new behaviour.
 *
 * @author
 */
public class CheeseDecorator extends SandWichDecorator{
    Sandwich currentSandwich;
   
    public CheeseDecorator(Sandwich sw){
        currentSandwich = sw;
    }
   
    @Override
    public String getDescription(){
        return currentSandwich.getDescription() + ", Cheese";
    }
    @Override
    public BigDecimal price() {
        return currentSandwich.price().add(new BigDecimal("0.50"));
    }
   
}


SandwichMaker.java
/**
 * Test class to demonstrate How Decorator Pattern in Java work together. This class
 * first creates a Sandwich and decorates it with extra cheese. This is nice example
 * of how to provide new functionalities to an object at runtime using Decorator Pattern.
 *
 * @author Javain Paul
 */
public class SandwichMaker {
   
    public static void main(String args[]){
       
        Sandwich mySandwich = new WhiteBreadSandWich("White bread Sandwich");
        System.out.printf("Price of %s is $%.2f %n", mySandwich.getDescription(), 
                                                     mySandwich.price());
       
        //adding extra cheese using Decorator Pattter
        mySandwich = new CheeseDecorator(mySandwich);
        System.out.printf("Price of %s is $%.2f %n", mySandwich.getDescription(), 
                                                     mySandwich.price());
    }
}

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

You can see that now price is easily calculated based upon the toppings and extras you add on Sandwich. These design patterns are very useful for writing code which 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 pattern like Decorator then you can take a look at the Design Pattern Library course on Pluralsight.





Key things about Decorator Design Pattern

Now, we have seen an example of decorator pattern in Java, we can quickly summarize few important things which are worth remembering while implementing or applying decorator pattern or even to answers design pattern questions like When to use 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 decorator class which accepts a base type of original object. like in this example constructor of CheeseDecorator accepts Sandwich object. 

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

4) The decorator pattern is also a good example of Open Closed design principle, which is one of the key principles from Uncle Bob's SOLID design principles. If you want to learn more about SOLID principles, please check the SOLID Principles of Object-Oriented Design course on Udemy. 

4) 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).

5) There is one disadvantage of 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 that which classes are main classes, and which are decorators, you tend to get a better understanding of overall structure. UML diagrams certain 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 lot's of use cases as well.

Further Learning
Design Pattern Library
From 0 to 1: Design Patterns - 24 That Matter - In Java
Java Design Patterns - The Complete Masterclass


Other Java Design Patterns tutorials you may like
  • 5 Free Courses to learn Object Oriented Programming (courses)
  • Difference between Factory and Dependency Injection Pattern? (answer)
  • How to create thread-safe Singleton in Java? (example)
  • How to implement the Strategy Design Pattern in Java? (example)
  • Difference between Factory and AbstractFactory Pattern? (example)
  • 18 Java Design Pattern Interview Questions with Answers (list)
  • Difference between Factory and Abstract Factory pattern in Java (answer)
  • How to design a Vending Machine in Java? (questions)
  • 20 System Design Interview Questions (list)
  • How to get a method of HashMap works internally in Java? (answer)
    Difference between Abstraction and Encapsulation in Java? (answer)
  • Difference between State and Strategy Design Pattern in Java? (answer)
  • Top 5 Courses to learn Design Patterns in Java (courses)
  • 5 Free Courses to learn Data Structure and Algorithms (courses)
Thanks a lot for reading this article so far. If you like this Decorator design pattern tutorial in Java then please share with your friends and colleagues. If you have any questions or feedback then please drop a note.

P. S. - If you want to learn more about design patterns and how they can help you to write better code in Java, I suggest you take a look at the Java Design Patterns and Architecture - a Free course on Udemy.

6 comments:

  1. Decorator Patter is true example of Composition over Inheritance. I used it a lot in my code, until I realized that, lots of small classes. Do you know any pattern or Strategy to merge Decorators together to gain benefit of this pattern and negate number of small classes?

    ReplyDelete
  2. Dude Try Some thing like
    A Sandwich Class.
    Toppings Abstract class with price as methods. And have multiple toppings like Cheese, Grilled, Sauces etc
    Let Sandwich class has Array of Toppings[]
    In Sandwich price add base price and Iterate over Toppings array to get price and Add them to sandwich.

    ReplyDelete
  3. for the beginner who start to learn design pattern this is a great place to learn design patterns with real world example.

    ReplyDelete
  4. Thanks Javin, and Thanks Ashish too. I was thinking how to do multiple customization.

    ReplyDelete
  5. And in which exactly real life situation will you have to recompile each time you change a price or add a new filling?

    ReplyDelete