Decorator Design Pattern – Implementation in Java

I have discussed Singleton Pattern, Observer Pattern and Factory Pattern in my previous posts. In this one I will be talking about Decorator Design Pattern.

What is a Decorator Pattern?

The dictionary definition of the verb decorate is make (something) look more attractive by adding extra items to it. Keeping in line with this definition, the decorator pattern allows you to enhance the functionality of an object without affecting other objects of the same class.

This is achieved via a combination of Abstract class and inheritance.

Advantages of Decorator Design Pattern

  1. It allows you to change functionality of a single object at runtime rather than the whole class.
  2. It embodies the single responsibility design principle, since one decorator class is responsible for a single thing.

Disadvantages of Decorator Design Pattern

  1. The application size can increase a lot as you will have many decorator classes.

Terminologies

  1. Component Interface – The base interface. This will be the interface whose concrete classes will be eventually decorated.
  2. Component Concrete Implementations – The concrete classes that implement the base interface.
  3. Decorator – An abstract class that will be the top hierarchical class for all the decorators that intend to be written for component interface.
  4. Concrete Decorators – The concrete classes that are actually adding functionality to the component concrete implementations.

UML diagram

In the above diagram, Shape is the Component Interface. The classes Rectangle and Circle are the concrete implementations of the shape interface. The shape decorator is an abstract class. The FillColor and BorderThickness classes are the concrete decorator classes that extend the ShapeDecorator class.

Java Implementation

Let us take an example application where we have to draw a shape with some extensions like a thick border or a different color.

Let us define the Shape interface and the two concrete implementations of the shape interface. This is same as the interface in the Factory Pattern post.

public interface Shape {
String draw();
}
view raw Shape.java hosted with ❤ by GitHub
public class Circle implements Shape {
@Override
public String draw() {
return "This is a circle !!!";
}
}
public class Rectangle implements Shape {
@Override
public String draw() {
return "This is a Rectangle !!!";
}
}

Now let us define the shape decorator class. This class will extend the shape interface. It will also have a reference to an object of a concrete Shape class. It can have a default implementation of the draw function.

public abstract class ShapeDecorator implements Shape{
protected Shape decoratedShape;
public ShapeDecorator(Shape decoratedShape){
this.decoratedShape = decoratedShape;
}
public void draw(){
decoratedShape.draw();
}
}

We will now define the two concrete implementations of the shape decorator, the FillColor class and the BorderThickness class. These classes will implement the draw function. It will extend the Concrete Shape’s draw function with whatever functionality it wants to add.

public class FillColor extends ShapeDecorator {
String color;
public FillColor(Shape decoratedShape, String color) {
super(decoratedShape);
this.color = color;
}
@Override
public void draw() {
decoratedShape.draw();
setColor();
}
private void setColor(){
System.out.println("Color: "+color);
}
}
public class BorderThickness extends ShapeDecorator {
Integer borderThickness;
public BorderThickness(Shape decoratedShape, Integer thickness) {
super(decoratedShape);
this.borderThickness = thickness;
}
@Override
public void draw() {
decoratedShape.draw();
setThickness();
}
private void setThickness(){
System.out.println("Border Width: "+borderThickness);
}
}

Bringing it all together.

public static void main(String[] args) {
Shape c = new Circle();
Shape redCircle = new FillColor(c, "Red");
redCircle.draw();
Shape r = new Rectangle();
Shape thickRectangle = new BorderThickness(r, 2);
thickRectangle.draw();
}

You can find the complete code on github.

Decorator Pattern in Java Library

The java.io package includes several decorators.

You can see an example of BufferedInputStream class that acts as a decorator on the FileInputStream.

public void main() {
// FileInputStream – responsible for reading the file
FileInputStream fileInputStream = new FileInputStream("file.txt");
// BufferedInputStream extends FilterInputStream and not FileInputStream, it is
// a decorator which enhances the functionality of the original object by wrapping over it.
BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);
// The read operation becomes buffered now
bufferedInputStream.read();
}

2 thoughts on “Decorator Design Pattern – Implementation in Java

Leave a comment