Blazeclan Technologies Recognized as a Niche Player in the 2023 Gartner® Magic Quadrant™ for Public Cloud IT Transformation Services

Simplifying Coding with the Decorator Design Pattern – When To & When Not to Use it!

As  explained in my previous Blog,  if you are working with group of developers  or individually implementing proper design concepts like the Singleton Design Pattern, you don’t have to spend time explaining the intricacies of a your solution.  If you are familiar with the Singleton pattern, you are much further along in the design process path. However, you need to know which Design Patterns fit the bill for the right solution for your Code. in the Singleton Example of the President in the last blog, that design pattern fit perfectly. But if you try to apply Singleton in the Pizza Solution example we’ll be discussing in this blog, it won’t work; so let us see how the Decorator Design Pattern Works with Code Snippets to help you through! 

 

Decoding the Decorator ! What is It & why Isn’t Anyone Using it?

The Decorator Design pattern is a prominent core Java design pattern and you can see many examples of it in JDK itself. JDK uses decorator patterns in the IO package where it has decorated the Reader and Writer Classes for various scenarios. BufferedReader and BufferedWriter are example of decorator design patterns in Java. So what is the Decorator Pattern & why Isn’t anyone using it?

Well, the Decorator pattern is very important to understand because once you know the techniques of decorating, you’ll be able to give your objects new responsibilities without making any code changes to the underlying classes. The Decorator Pattern allows class behavior to the decorated dynamically. It’s a structural design pattern as it’s used to form large object structures across many disparate objects. The concept of decorator is that it adds additional attributes to an object dynamically.

The original definition provided in original Gang of Four book on Design Patterns states:

Allows for the dynamic wrapping of objects in order to modify their existing responsibilities and behaviors 
Decorator pattern achieves a single objective of dynamically adding responsibilities to any object.

 

So When is it Right to Use the Decorator Pattern ?

I found that Decorator Design Pattern has several requirement indicators to suggest that it is potential solution e.g.

  • When we have an object that requires the extension ex. a window control that requires additional “optional” features like scrollbars, titlebar and statusbar.
  • When Several objects that support the extension by “decoration”. Usually, those objects share a common interface, traits, or superclass, and sometimes, additional, intermediate super-classes .
  • The decorated object (class or prototype instantiation), and the decorator objects have one or several common features. In order to ensure that functionality, the decorated object & the decorators have a common interface, traits, or class inheritance.

 

Why do we use the decorator design pattern? Pizzas to the Rescue !

The answer is if anyone wants to add some functionality to an individual object or change the state of a particular object at the run time it’s not possible to provide the specific behavior to all the objects of that class at the design time by the help of inheritance or using subclasses, but Decorator pattern makes it possible to provide individual objects of the same class a specific behavior or state at the run time. This doesn’t affect other objects of the same java class

Consider a case of a pizza shop. A pizza shop will sell few pizza varieties and they will also provide a range of toppings in the menu. Now imagine a situation wherein if the pizza shop has to provide prices for each combination of pizza and topping. Even if there are four basic pizzas and 8 different toppings, the application would go crazy maintaining all these concrete combination of pizzas and toppings.

In comes the Decorator Pattern: 

As per this, you will implement toppings as decorators and pizzas will be decorated by those toppings’ decorators. Practically each customer would want toppings of his desire and final bill-amount will be composed of the base pizzas and additionally ordered toppings. Each topping decorator would know about the pizzas that it is decorating and it’s price. GetPrice() method of Topping object would return cumulative price of both pizza and the topping.

Here’s a code-example of explanation above.

Decorator Pattern Example

The below is an interface depicting an Pizza. I have kept things as simple as possible so thatthe focus will be on understanding the design pattern.

interface Pizza { 
    int getPrice();
}
 Following class is a concrete implementation of this interface. This is the base class on     which the decorators will be added.

class PlainPizza implements Pizza {

 @Override
 public int getPrice() {
      return 50;
 }
}
Following class is the decorator class. It is the core of the decorator design pattern. It    contains an attribute for the type of interface. Instance is assigned dynamically at the      creation of decorator using its constructor. Once assigned that instance method will be       invoked.

abstract class ToppingDecorator implements Pizza {
 Pizza toppingPizza;
  public ToppingDecorator(Pizza toppindPizza) { 
   this.toppingPizza = toppindPizza; 
 }
}

Following three classes are similar. These are three decorators, concrete class implementing the abstract decorator.

 class CheeseToppings extends ToppingDecorator {

 public CheeseToppings(Pizza toppindPizza) { 
    super(toppindPizza);
 }

 @Override public int getPrice() { 
    return this.toppindPizza.getPrice()+20; 
 }
}
class ChickenToppings extends ToppingDecorator {

 public ChickenToppings(Pizza toppindPizza) { 
  super(toppindPizza); 
 }

 @Override 
 public int getPrice() { 
  return this.toppindPizza.getPrice()+ 15; 
 }
}
class MushroomsToppings extends ToppingDecorator {

 public MushroomsToppings(Pizza toppindPizza) { 
   super(toppindPizza);
 }

  @Override 
  public int getPrice() { 
     return this.toppindPizza.getPrice()+25; 
  }
}
public class DecoratorDemo {
 public static void main(String[] args) {
 Pizza pizza=new PlainPizza();
 System.out.println("Plain Pizza Rs."+ pizza.getPrice());

 pizza=new CheeseToppings(pizza);
 System.out.println("Pizza with Cheese Toppings Rs."+ pizza.getPrice());

 pizza=new ChickenToppings(pizza);
 System.out.println("Pizza with Cheese and Chicken Toppings Rs."+pizza.getPrice());

 pizza=new MushroomsToppings(pizza);
 System.out.println("Pizza with Cheese, Chicken and Mushroom Toppings Rs."+pizza.getPrice());
 }

}

Output:

Plain Pizza Rs.50
Pizza with Cheese Toppings Rs.70
Pizza with Cheese and Chicken Toppings Rs.90
Pizza with Cheese, Chicken and Mushroom Toppings Rs.115

 

Simplifying Web Services Development with the Decorator Pattern

Developing Web services can be complex. Even more complex can be designing Web services implementations that allow you to reuse common code and abstract common functionality. The decorator pattern is a flexible way to layer functionality onto your services without having to go through the costly code/test/deploy cycle. Developing custom steps and deploying them in policies simplifies your Web services project by freeing your developers to focus on business functionality and not just boilerplate code.

 

So is there an Issue with the Decorator Pattern?

The Decorator pattern is best when the decorators modify the behavior of the methods in the interface. A decorator can add methods, but added methods don’t carry through when you wrap in another decorator.

In this example, indeed if you have

Employee emp = new TeamLeader(new TeamMember(new EmployeeImpl()));

The emp doesn’t have access to the TeamMember specific methods.

This means that the pattern may not be a good choice for the situation.

You can of course do

TeamMember member = new TeamMember(new EmployeeImpl());
TeamLeader leader = new TeamLeader(member);

and then access the specific methods from the right variable and the interface methods from either. But I would say this is probably just not an appropriate use of this pattern.

Stay Tuned for more of our Design Mantras in the later blogs ! Subscribe to Our Blogs.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.