Tuesday, April 19, 2011

Design patterns in Java - Decorator

Introduction


As holy grail of Java OO design book (GoF - Elements Of Reusable OO Software) say: "Decorator design pattern is intended to add additional responsibility to an object dynamically. This design pattern is also known as Wrapper".

So in another words this design pattern enable object inheritance at runtime. It achieve this by using interface inheritance and class composition.

Implementation

In Java classes java.io package also use decorator design pattern. For example:

File f = new file("d:\something.txt");
//Here FileInputStream "inherits" File class.
FileInputStream is = new FileInputStream(f);
//Here we add buffering capability to FileInputStream using decorator.
BufferedInputStream bis = new BufferedInputStream(fi);

I must point out that Decorator design pattern can also be used to remove responsibility from object (our example will not include this case).

Following code represent simple implementation of this pattern in Java.

Interface that will be our default "object". This object will be decorated (extended).
/**
 * Basic phone that can do only basic ringing.
 */
public interface IPhone {
    
    void announceCall();

    void announceMessage();

}
Decorator interface that extends our default "object" interface. So instead of static inheritance in implementation we create interface inheritance.
/**
 * Decorator that adds additional functionality to basic Phone.
 */
public interface IPhoneDecorator extends IPhone {

    void vibrate(int milliseconds);

    void flashLED();
}
Concrete implementation of our "default" object (nothing interesting, just simple interface implementation).
public class Phone implements IPhone {

    /*
     * This Phone announce call only by ringing.
     */
    public void announceCall() {
        System.out.println("Ring!");
    }

    /*
     * Phone announce message by makeing some sound.
     */
    public void announceMessage() {
        System.out.println("Make a sound!");
    }
}
Concrete decorator implementation that implements all operations. It delegate part of functionality to our "default" object and add more functionality of his own. It has one filed named phone which represent our "default" object implementation to which we will delegate stuff.
/**
 * Concrete decorator class that adds additional functionality.
 * @author jan.krizan
 */
public class UpgradePhoneDecorator implements IPhoneDecorator {

    private IPhone phone;

    /**
     * Constructor through which client put
     * instance that will be decorated.
     * @param phone
     */
    public UpgradePhoneDecorator(IPhone phone) {
        super();
        this.phone = phone;
    }

    public void vibrate(int milliseconds) {
        System.out.println("Vibrating for " + milliseconds + " milliseconds.");
    }

    public void flashLED() {
        System.out.println("Make a LED flash!");
    }

    public void announceCall() {
        //Delegate basic functionality to Phone clase.
        phone.announceCall();
        //Add additional functionality.
        vibrate(1500);
    }

    public void announceMessage() {
        //Delegate basic functionality to Phone clase.
        phone.announceMessage();
        //Add additional functionality.
        flashLED();
    }
}
We can now see what can our "default" object do before and after it has been decorated. You can see that we provide phone instance to decorator constructor and by using polymorphism (dynamic binding) we delegate basic work to our "default" object.
public static void main(String[] args) {
        IPhone oldPhone = new Phone();
        System.out.println("What can old phone do!");
        oldPhone.announceCall();
        oldPhone.announceMessage();
        System.out.println();
        IPhoneDecorator decoratedPhone = new UpgradePhoneDecorator(oldPhone);
        System.out.println("What can new phone do!");
        decoratedPhone.announceCall();
        decoratedPhone.announceMessage();
    }

Hope you like this!


Here is output (example uses ANT):
run:
What can old phone do!
Ring!
Make a sound!

What can new phone do!
Ring!
Vibrating for 1500 milliseconds.
Make a sound!
Make a LED flash!
BUILD SUCCESSFUL (total time: 0 seconds)

2 comments:

  1. Great post man, you have indeed covered topic quite well. What is most important point with decorator is that it affect only individual object and not all object which itself a big control and flexibility inheritance doesn't offer. See here for another example of decorator pattern in Java.

    ReplyDelete
  2. Delegation design pattern is used by multiple classes to work collaboratively. Java emphasizes on principal of single responsibility i.e. One class should maintain code only for one specific business responsibility For example An Customer class should be responsible only for managing customer data If it starts managing the customer Orders as well It violates the principal of single responsibility. - See more at: http://www.blog.newventurewebsites.com/delegate-design-pattern-in-php/#comment-437

    http://efectivejava.blogspot.in/2013/08/delegation-design-pattern.html

    ReplyDelete