Core Java

Decorator Design Pattern In Java

A decorator design pattern allows dynamically attaching the additional responsibilities or behaviors to an object at runtime. It is a structural pattern and makes use of aggregation to combine those behaviors.

In this tutorial, we’ll learn to implement the decorator pattern.

UML Diagram:

Let’s start by looking at the UML representation of a decorator pattern:

The ConcreteComponent class is the one for which we’ll like add additional behaviors at runtime. The ConcreteDecorator1, ConcreteDecorator2, … are the decorator classes which hold the logic to decorate a given Component.

Note that the abstract Decorator classhas a Component. In other words, it aggregates any other type of component which allows us to stack components one on the top of the other.

Moreover, both the ConcreteComponent and Decorator classes implement a common interface – Component.

Example Implementation:

Let’s say we are selling a gift item. Once a user selects a gift item, there can be multiple ways just to decorate that gift item say with a red or a blue ribbon, purple or green gift wrap, etc.

Rather than creating a class for each possible combination, it’s a good idea to implement it using a decorator pattern.

So, let’s create our GiftComponent interface:

1
2
3
public interface GiftComponent {
    void pack();
}

Also, let’s write our GiftItem class which is a concrete implementation of the GiftComponent:

1
2
3
4
5
6
public class GiftItem implements GiftComponent {
  
    public void pack() {
        System.out.println("Putting it in a box");
    }
}

Implementing Abstract Decorator:

Now that we have a GiftItem that we’ll like to decorate, let’s define our abstract GiftDecorator class:

01
02
03
04
05
06
07
08
09
10
11
public abstract AbstractGiftDecorator implements GiftComponent {
    protected GiftComponent gift;
  
    public AbstractGiftDecorator(GiftComponent gift) {
        this.gift = gift;
    }
     
    public void pack() {
        this.gift.pack();
    }
}

The gift decorator has a single instance of the gift component. This enables stacking decorators on top of one another.

Creating Multiple Decorators:

Finally, we can create as many custom decorators as we want.

Let’s create a few gift wraps:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class PurpleWrapper extends AbstractGiftDecorator {
  
    public PurpleWrapper(GiftComponent gift) {
        super(gift);
    }
  
    public void pack() {
        super.pack();
        System.out.println("Purple wrapper");
    }
}
  
public class RedWrapper extends AbstractGiftDecorator {
  
    public RedWrapper(GiftComponent gift) {
        super(gift);
    }
  
    public void pack() {
        super.pack();
        System.out.println("Red wrapper");
    }
}

And a few types of ribbons for further decoration:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class BlueRibbon extends AbstractDecorator {
  
    public BlueRibbon(GiftComponent gift) {
        super(gift);
    }
  
    public void pack() {
        super.pack();
        System.out.println("Blue ribbon");
    }
}
  
public class PinkRibbon extends AbstractDecorator {
  
    public PinkRibbon(GiftComponent gift) {
        super(gift);
    }
  
    public void pack() {
        super.pack();
        System.out.println("Pink Ribbon");
    }
}

Testing Our Implementation:

Let’s now test out our implementation to see what happens:

1
2
3
4
5
6
7
// client code
GiftComponent gift = new GiftItem();
GiftComponent giftWithPurpleWrapper = new PurpleWrapper(gift);
GiftComponent giftWithPurpleWrapperAndPinkRibbon =
  new PinkRibbon(giftWithPurpleWrapper);
  
giftWithPurpleWrapperAndPinkRibbon.pack();

As we can see, we are now able to easily and elegantly wrap the gift item in the way we want just by chaining the decorators. The above code will print:

1
2
3
Putting it in a box
Purple Wrapper
Pink Ribbon

Conclusion:

The decorator design pattern uses aggregation as a substitute for a pure inheritance. It allows us to dynamically add behaviors to an object. It takes away the overhead of creating a separate class for every possible combination thereby significantly reducing the number of classes.

Also, it adheres to the Single Responsibility Principle which states that every class must exactly do one thing. The classes like java.io.BufferedReader, java.io.FileReader are designed using the decorator design pattern.

Published on Java Code Geeks with permission by Shubhra Srivastava, partner at our JCG program. See the original article here: Decorator Design Pattern In Java

Opinions expressed by Java Code Geeks contributors are their own.

Shubhra Srivastava

Shubhra is a software professional and founder of ProgrammerGirl. She has a great experience with Java/J2EE technologies and frameworks. She loves the amalgam of programming and coffee :)
Subscribe
Notify of
guest

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

2 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
granny
5 years ago

I’d like to make three points in response to yours, though. 1. As you get to more mission-critical applications, you may need to add otherwise redundant programming styles to your code to add assurance. 2. If your methods are so long that you can’t see the structure at a glance (I’m taking 5 lines of code as a “large method”), then the real problem is you need shorter methods, not you need bullet-proof structures. 3. The fault you described with a medical device is as much a case of missing unit-tests as it is a case of missing a return… Read more »

hibra
hibra
4 years ago

public class BlueRibbon

extends AbstractDecorator
should be
public class BlueRibbon

extends AbstractGiftDecorator

Back to top button