The Decorator Design Pattern is a special type of pattern one of the Structural Patterns, that allows you to add and removing behaviours to an individual object at the run-time dynamically or statically without changing the existing behaviour of other associated objects from the same class.
In software engineering, the common intent of all GOF structural patterns is to simplify the complex relationship between objects and classes in a flexible in the enterprise application. This Decorator pattern does this without violating the Single Responsibility Principle of the SOLID principle of object-oriented programming.
According to the Gang of Four:
Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality.
This design pattern uses the compositions over the inheritance for objects associations, it allows you to divide the functionality into different concrete classes with a unique area of concern.
There is a requirement of the business or might be some future planning for the product to extend behaviour by adding the new functionality to an object, to achieving it you could use inheritance to extend the behaviour of an object. But inheritance should be done at compile time and is also available for other instances of that class. And because of code modification required in case of inheritance, which is a violation of the Open Closed Principle. Instead, to avoid this violation of SOLID principle, you can attach new responsibility to an object dynamically. This is exactly the situation, the decorator design pattern comes into the picture and addresses this issue in a very flexible way.
also read:
Let’s see the following figure that illustrates the classes and objects participating in this pattern are:
Component (Account)
ConcreteComponent (SavingAccount)
Decorator (AccountDecorator)
ConcreteDecorator (SeniorCitizen, Privilege)
There are following pros of using this decorator pattern.
There are following pros of using this decorator pattern.
Let’s look into the following example how to implement this design pattern into a real case study.
Consider a Bank offers multiple accounts with different benefits to the customers, it divided the customers into three categories as like Senior Citizen, Privilege and Young. Bank launched a scheme to the Saving account for Senior citizen as bank provides a medical insurance of up to $1,000 for Senior Citizen if they open saving account in this bank, similarly bank also provides a scheme to the privilege customers as an accident insurance of up to $1,600 and an overdraft facility of $84. There is no scheme for the Young.
To address the new requirement, we can add new subclasses of SavingAccount, one each to represent a saving account with additional benefits as decoration, and this is how our design looks like now. Clearly, this design is flawed, but this is an ideal use case for the decorator pattern. Decorator design pattern allows you to add run time dynamically behaviour, in this case, I will create an abstract AccountDecorator class to implement Account. And furthermore, I will create the SeniorCitizen and Privilege class extend and AccountDecorator because Young does not have any extra benefits, so class SavingClass does not extend AccountDecorator. This is how the design will be.
In the figure above, it follows the Decorator Design Pattern by creating AccountDecorator as a Decorator in this pattern, and focus on the important thing to observe the relationship between Account and AccountDecorator. This relationship as below:
Let’s look into the following sample codes to demonstrate the Decorator Design Pattern.
Account.java
package com.doj.patterns.structural.decorator; public interface Account { String getTotalBenefits(); }
SavingAccount.java
package com.doj.patterns.structural.decorator; /** * @author Dinesh.Rajput * */ public class SavingAccount implements Account { @Override public String getTotalBenefits() { return "This account has 4% interest rate with per day $5000 withdrwal limit"; } }
CurrentAccount.java
package com.doj.patterns.structural.decorator; /** * @author Dinesh.Rajput * */ public class CurrentAccount implements Account{ @Override public String getTotalBenefits() { return "There is no withdrwal limit for current account"; } }
AccountDecorator.java
package com.doj.patterns.structural.decorator; /** * @author Dinesh.Rajput * */ public abstract class AccountDecorator implements Account{ abstract String applyOtherBenefits(); }
Privilege.java
package com.doj.patterns.structural.decorator; /** * @author Dinesh.Rajput * */ public class Privilege extends AccountDecorator { Account account; public Privilege(Account account) { super(); this.account = account; } @Override public String getTotalBenefits() { return account.getTotalBenefits() + " other benefits are "+applyOtherBenefits(); } @Override String applyOtherBenefits() { return " an accident insurance of up to $1,600 and an overdraft facility of $84"; } }
DecoratorPatternMain.java
package com.doj.patterns.structural.decorator; /** * @author Dinesh.Rajput * */ public class DecoratorPatternMain { public static void main(String[] args) { /*Saving account with no decoration*/ Account basicSavingAccount = new SavingAccount(); System.out.println(basicSavingAccount.getTotalBenefits()); /*Saving account with senior citizen benefits decoration*/ Account seniorCitizenSavingAccount = new SavingAccount(); seniorCitizenSavingAccount = new SeniorCitizen(seniorCitizenSavingAccount); System.out.println(seniorCitizenSavingAccount.getTotalBenefits()); /*Saving account with privilege decoration*/ Account privilegeCitizenSavingAccount = new SavingAccount(); privilegeCitizenSavingAccount = new Privilege(privilegeCitizenSavingAccount); System.out.println(privilegeCitizenSavingAccount.getTotalBenefits()); } }
This account has 4% interest rate with per day $5000 withdrwal limit This account has 4% interest rate with per day $5000 withdrwal limit other benefits are an medical insurance of up to $1,000 for Senior Citizen This account has 4% interest rate with per day $5000 withdrwal limit other benefits are an accident insurance of up to $1,600 and an overdraft facility of $84
There are following implementations of this pattern.
Strategy Design Patterns We can easily create a strategy design pattern using lambda. To implement…
Decorator Pattern A decorator pattern allows a user to add new functionality to an existing…
Delegating pattern In software engineering, the delegation pattern is an object-oriented design pattern that allows…
Technology has emerged a lot in the last decade, and now we have artificial intelligence;…
Managing a database is becoming increasingly complex now due to the vast amount of data…
Overview In this article, we will explore Spring Scheduler how we could use it by…