Decorator design pattern in Java

In this article I write about the Decorator Design Pattern. This is a very nice pattern if you want to extend class behavior at runtime.

About the Decorator Design pattern

The concept of the decorator pattern is that it adds additional attributes to objects dynamically. This way you do not need to subclass the base to add extra functionality. This is good because with subclassing (extending) you change the behavior of all instances of the given class however you may only want some objects (instances of a given class) to change their behavior.

The Gang of Four (GoF) book states the following about this pattern:

Allows for the dynamic wrapping of objects in order to modify their existing responsibilities and behaviors.

When to use the pattern?

Knowing a pattern is good but as I mentioned earlier: use it with responsibility. Consider the following prior decorating everything in your Java project:

  • Should concrete implementations be decoupled from behaviors and responsibilities?
  • Should object responsibilities and behaviors be dynamically modifiable?

If you answer “Yes!” to the questions it may be a good idea to have subclasses but too many subclasses and too deep object-hierarchies are bad practice so you should avoid this.

How to use Decorator pattern?

First of all you need a common denominator for your objects which you can extract to an interface. This gives the contract to all of the users that the implementations have a defined set of methods which can be called.

Then you can create concrete implementors of this interface which are just normal citizens of your Java world.

And you can create a decorator which implements this interface too and has an attribute of the same interface — the object which will be decorated with this behavior. And this decorator implementation (which can be an abstract class to extend its behavior of course) implements the contract-method of the interface and implements some extra behavior to the default implementation of the attribute’s.

Seems complex? I bet with an example it will be very easy to understand.

Example

First of all let’s create the interface which gives us the contract:

/**
 * Interface to create an app
 *
 * @author GHajba
 *
 */
public interface App {

    /**
     * This method creates an app for our app store. Seems silly and broken by design to have the App develop itself but
     * for this example it fits the purpose.
     */
    void developApp();
}

Now add a simple implementation of this interface which implements the contract method:

/**
 * @author GHajba
 *
 */
public class IOSApp implements App {

    @Override
    public void developApp() {
        System.out.println("Developing an iOS app");
    }
}

We are all set and have an interface with an implementation so let’s try how it works:

/**
 * This is the main entry point of the application
 *
 * @author GHajba
 *
 */
public class AppStore {

    public static void main(String... args) {
        final App app = new IOSApp();
        app.developApp();
    }
}

Running this application yields the following result:

Developing an iOS app

This is quite straightforward so let’s take the next step.

We introduce the decorator. We make it for now abstract:

/**
 * This is the basic implementation for our decorator. It is abstract so it does not need to implement the contract
 * method "developApp()".
 *
 * However it has the delegate which will be decorated later.
 *
 * @author GHajba
 *
 */
public abstract class AppDecorator implements App {
    /**
     * This is the delegate to decorate. It is package-private so the subclasses can access it so we do not need
     * getters/setters and a constructor. However I would add one if I would write this decorator in my daily job.
     */
    App delegate;
}

And create two subclasses of this abstract Decorator to have interchangeable behavior:

/**
 * This creates a decorated App with TV extension.
 *
 * @author GHajba
 *
 */
public class TVAppDecorator extends AppDecorator {

    /**
     * A required constructor to set the delegate for this app.
     *
     * @param delegate
     *            the delegate which should be decorated.
     */
    public TVAppDecorator(App delegate) {
        this.delegate = delegate;
    }

    @Override
    public void developApp() {
        this.delegate.developApp();
        System.out.println("Adding TV extension...");
    }
}

/**
 * This implementation of the decorator adds a Watch extension to the provided app.
 *
 * @author GHajba
 *
 */
public class WatchAppDecorator extends AppDecorator {

    /**
     * A required constructor to set the delegate for this app.
     *
     * @param delegate
     *            the delegate which should be decorated.
     */
    public WatchAppDecorator(App delegate) {
        this.delegate = delegate;
    }

    @Override
    public void developApp() {
        this.delegate.developApp();
        System.out.println("Adding Watch extension...");
    }
}

As you can see, the implementations of the decorator both implement the contract method a way different so let’s see what the application’s output is if we use these decorators:

/**
 * This is the main entry point of the application
 *
 * @author GHajba
 *
 */
public class AppStore {

    public static void main(String... args) {
        final App tvApp = new TVAppDecorator(new IOSApp());
        tvApp.developApp();

        System.out.println("------");

        final App watchApp = new WatchAppDecorator(new IOSApp());
        watchApp.developApp();
    }
}

Developing an iOS app
Adding TV extension…
——
Developing an iOS app
Adding Watch extension…

Naturally as I mentioned previously the decorator does not need to be an abstract class it can be a normal class too:

/**
 * This is the decorator implementation which implements the decorator pattern by itself.
 *
 * @author GHajba
 *
 */
public class SimpleDecorator implements App {

    private final App delegate;

    /**
     * A required constructor to set the delegate for this app.
     *
     * @param delegate
     *            the delegate which should be decorated.
     */
    public SimpleDecorator(App delegate) {
        this.delegate = delegate;
    }

    @Override
    public void developApp() {
        System.out.println("Preparing extra content...");
        this.delegate.developApp();
        System.out.println("Fine-tuning the app to be more perfect...");
    }
}

Now let’s see how this Decorator is used:

/**
 * This is the main entry point of the application
 *
 * @author GHajba
 *
 */
public class AppStore {

    public static void main(String... args) {
        final App perfectApp = new SimpleDecorator(new IOSApp());
        perfectApp.developApp();
    }
}

In this case the output would be the following:

Preparing extra content…
Developing an iOS app
Fine-tuning the app to be more perfect…

Conclusion

The Decorator Pattern is very useful in some cases but it has its downsides too. For example the Decorator and its enclosed components are not identical, this means that the instanceof comparison will fail in this particular case. So keep an eye open when you use this pattern!

Leave a Reply

Your email address will not be published. Required fields are marked *

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