Decorator Pattern

Also known as wrapper, is used to extend the functionality of an object dynamically without changing the original class source or using inheritance. This is accomplished by creating an object wrapper referred to as a Decorator around the actual object.

The decorator implements the new functionality, but for functionality that is not new, the original (wrapped) class is used using a reference from decorator to the main object. The decorating class must have the same interface as the original class. The Decorator object adds some additional functionality before or after forwarding requests to the underlying object. This ensures that the additional functionality can be added to a given object externally at runtime without modifying its structure.

Decorator is more flexible than inheritance as it doesn't need subclassing and works at runtime.

decorator.jpeg
/*
Suppose we want to add extra functionality to HtmlLogger but we do not want to extend it as extending can grow too big.
That means if "x,y,z,t implements Logger" then adding functionality to x,y,z,t would need having 
"x1 extends x, y1 extends y, z1 extends z, t1 extends t".
*/
 
public interface Logger {
    public void log(String mgs);
}
 
//some concrete logger
public class HtmlLogger implements Logger{
    @Override
    public void log(String mgs) {
 
    }
}
 
//Can be interface or a normal class. A normal class does the job in most of the cases.
public abstract class LogDecorator implements Logger{
    public Logger decoratedLogger;//Decorator has a reference to the class being decorated
}
 
//Concrete decorator - aimed to decorate concrete loggers.
//EncryptedLogger  does not need to extend HtmlLogger to add more functionality to it.
public class EncryptedLogger extends LogDecorator{
 
    public EncryptedLogger(Logger logger){
        super.decoratedLogger = logger;
    }
 
    @Override
    public void log(String mgs) {
        //some additional work
        decoratedLogger.log("some message");
        //some additional work
    }
}
 
public class Client {
 
    public static void main(String[] args) {
        Logger logger = new  EncryptedLogger(new HtmlLogger());
        logger.log("some log");
    }
}

Related Patterns:

  • Adapter: A decorator is different from an adapter in that a decorator only changes an object's responsibilities, not its interface; an adapter will give an object a completely new interface.
  • Composite: A decorator can be viewed as a degenerate composite with only one component. However, a decorator adds additional responsibilities—it isn't intended for object aggregation.
  • Strategy: A decorator lets you change the skin of an object; a strategy lets you change the guts. These are two alternative ways of changing an object. Strategy knows about possible extensions but decorator does not know that is being decorated. Strategies are a better choice in situations where the Component class is heavyweight and using the Decorator pattern is so costly.
Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License