Saturday, October 5, 2019

Decorator Design Pattern In Java

Greetings!

Decorator desgin pattern is a structural design pattern.
This is a pretty standards pattern in Java, especially in code related to input/output classes such as FileReader, BufferedReader.

Full source code for this blog post is at my github account. [source-code]

GoF definition.
"Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to sub classing for extending functionality."



This is very powerful pattern to add extra funtionality to an object through composition. Interestingly, we are doing it at runtime.
This gives us an alternative to subclassing.

"Subclassing adds behaviour at compile time, decorator adds behaviour at run time."

When we use inheritance to add additional functionality, we may end with long heirarchy with too many classes. With decorator design pattern, we only need to create base and additional functionality can be added by decorating that base.
This is sometimes called as wrapper. Term used by Josua Bloch in his famous book is Forwarder.

"Inheritance is one form of extension, but not necessarily the best way to achieve flexibility in our designs."

Steps

  • Create base interface.
  • Implement it to add core functionality.
  • Create abstract class by implementing the interface which also compose the same interface.
  • Extend abstract class to add extra functionality.

Working Example

Let's decorate what is above us. The Sky! Sky mainly has two forms. Noon and night. Depending on days condition Sky is decorated with clouds, stars.

We can start with our Sky.

package com.slmanju.patterns;

public interface Sky {

    void draw();

}


Night sky have dark behaviour.

package com.slmanju.patterns;

public class NightSky implements Sky {

    @Override
    public void draw() {
        System.out.println("Drawing sky with black color");
    }

}


Now we can have our AbstractSky which acts as the base decorator.

package com.slmanju.patterns;

public abstract class AbstractSky implements Sky {

    protected Sky sky;

    public AbstractSky(Sky sky) {
        this.sky = sky;
    }

}


Let's add some stars into the Sky.

package com.slmanju.patterns;

public class StarSky extends AbstractSky {

    public StarSky(Sky sky) {
        super(sky);
    }

    @Override
    public void draw() {
        sky.draw();
        System.out.println("Drawing stars");
    }

}


Now it is time to decorate our Sky.

package com.slmanju.patterns;

public class App  {

    public static void main(String[] args) {
        Sky night = new NightSky();
        night = new StarSky(night);
        night = new CloudySky(night);
        night.draw();

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

        Sky sky = new RainySky(new CloudySky(new NoonSky()));
        sky.draw();
    }

}


Remember;
  • Classes should be open for extension but closed for modification.
  • You can extend your core functionality by decorating it.

Happy coding :)

No comments:

Post a Comment