Decorator pattern dynamically changes the functionality of an object at run-time without creating new object rather by adding behavior and attribute to existing Object.

Why Decorator Pattern?

It allows adding new functionality to an existing object without altering its original class. This pattern involves wrapping the original object in a decorator class, which has the same interface as the object it decorates. The decorator class then adds its behavior to the object during runtime, allowing for increased flexibility and modularity in programming.

When Decorator Pattern?
If you want to add additional functionality to an existing object (i.e. already instantiated class at runtime), as opposed to object’s class and/or subclass then Decorator pattern should be used. It is easy to add functionality to an entire class of objects by subclassing an object’s class, but it is impossible to extend a single object this way. With the Decorator Pattern, you can add functionality to a single object and leave others like it unmodified.

How Decorator Pattern Implemented?

  1. Create a Interface with a concrete base class which implements Interface. This base class has only default constructor
  2. Create Concrete Decorator Classes which implements Interface
  3. The Decorator keeps appending the Logs and the log method would be invoked only once after all the appending is done

Logger.java

public interface Logger {
    void  log(String msg);
}

BasicHtmlLogger.java

public class BasicHtmlLogger implements  Logger {
    public BasicHtmlLogger() {
    }

    @Override
    public void log(String msg) {
        System.out.println("<html>" + msg + "</html>");
    }
}

HTMLLoggerDecoratorBold.java

public class HTMLLoggerDecoratorBold implements Logger {
    Logger logger;

    public HTMLLoggerDecoratorBold(Logger logger) {
        this.logger = logger;
    }

    @Override
    public void log(String msg) {
        logger.log("<bold>"+ msg+ "</bold>");
    }
}

HTMLLoggerDecoratorItalic.java

public class HTMLLoggerDecoratorItalic implements Logger {
    Logger logger;

    public HTMLLoggerDecoratorItalic(Logger logger) {
        this.logger = logger;
    }

    @Override
    public void log(String msg) {
        logger.log("<italic>"+ msg+ "</italic>");
    }
}

HTMLLoggerDecoratorUnderline.java

public class HTMLLoggerDecoratorUnderline implements Logger {
    Logger logger;

    public HTMLLoggerDecoratorUnderline(Logger logger) {
        this.logger = logger;
    }

    @Override
    public void log(String msg) {
        logger.log("<underline>"+ msg+ "</underline>");
    }
}

Client.java

public class Client {
    public static void main(String[] args) {
        Logger objBasicLogger = new BasicHtmlLogger();
        Logger objBoldLogger = new HTMLLoggerDecoratorBold(objBasicLogger);
        Logger objItalicLogger = new HTMLLoggerDecoratorItalic(objBasicLogger);
        Logger objUnderlineLogger = new HTMLLoggerDecoratorUnderline(objBasicLogger);

        Logger objBoldItalicLogger = new HTMLLoggerDecoratorItalic(objBoldLogger);

        objBasicLogger.log("Logging Msg without Formatting"); //Basic Logging
        objUnderlineLogger.log("Logging Msg with Underline"); //Basic Logging + Underline
        objBoldLogger.log("Logging Msg with Bold Formatting"); //Basic Logging + Bold
        objItalicLogger.log("Logging Msg with Italic Formatting"); //Basic Logging + Italic
        objBoldItalicLogger.log("Logging Msg with Bold, Italic Formatting"); //Basic Logging + Bold + Italic
    }
}

Output

<html>Logging Msg without Formatting</html>
<html><underline>Logging Msg with Underline</underline></html>
<html><bold>Logging Msg with Bold Formatting</bold></html>
<html><italic>Logging Msg with Italic Formatting</italic></html>
<html><bold><italic>Logging Msg with Bold, Italic Formatting</italic></bold></html>

Below we have one more example of Decorator Pattern

Gift.java

public interface Gift {
    public String addGift();
    public Integer addGiftCost();
}

BasicGift.java

public class BasicGift implements Gift {
    @Override
    public String addGift() {
        return "Gift Item";
    }

    @Override
    public Integer addGiftCost() {
        return 50;
    }
}

GiftFlowersDecorator.java

public class GiftFlowersDecorator implements Gift {
    Gift gift;

    public GiftFlowersDecorator(Gift gift) {
        this.gift = gift;
    }

    @Override
    public String addGift() {
        if(gift != null){
            return gift.addGift() + " + Flowers ";
        }

        return " Flowers to gift Item";
    }

    @Override
    public Integer addGiftCost() {

        if(gift != null){
            return gift.addGiftCost() + 10;
        }

        return 5;
    }
}

GiftGreetingsCardDecorator.java

public class GiftGreetingsCardDecorator implements Gift {
    Gift gift;

    public GiftGreetingsCardDecorator(Gift gift) {
        this.gift = gift;
    }

    @Override
    public String addGift() {
        if(gift != null){
            return gift.addGift() + " + Greetings Card";
        }

        return " Greetings Card";
    }

    @Override
    public Integer addGiftCost() {

        if(gift != null){
            return gift.addGiftCost() + 7;
        }

        return 5;
    }
}

GiftWrapDecorator.java

public class GiftWrapDecorator implements Gift {
    Gift gift;

    public GiftWrapDecorator(Gift gift) {
        this.gift = gift;
    }

    @Override
    public String addGift() {
        if(gift != null){
            return gift.addGift() + " + Wrapper ";
        }

        return " wrapping gift Item";
    }

    @Override
    public Integer addGiftCost() {

        if(gift != null){
            return gift.addGiftCost() + 5;
        }

        return 5;
    }
}

BuyGiftOnline.java

public class BuyGiftOnline {
    public static void main(String[] args) {
        Gift objGift = new BasicGift();
        System.out.println(objGift.addGift() + " = " + objGift.addGiftCost());

        Gift objGiftWithWrapper = new GiftWrapDecorator(objGift);
        System.out.println(objGiftWithWrapper.addGift() + " = " + objGiftWithWrapper.addGiftCost());

        Gift objGiftWithWrapperAndFlowers = new GiftFlowersDecorator(objGiftWithWrapper);
        System.out.println(objGiftWithWrapperAndFlowers.addGift() + "= " + objGiftWithWrapperAndFlowers.addGiftCost());

        Gift objGiftWithWrapperAndInvitation= new GiftGreetingsCardDecorator(objGiftWithWrapper);
        System.out.println(objGiftWithWrapperAndInvitation.addGift() + " = " + objGiftWithWrapperAndInvitation.addGiftCost());
    }
}

Output

Gift Item = 50
Gift Item + Wrapper  = 55
Gift Item + Wrapper  + Flowers = 65
Gift Item + Wrapper  + Greetings Card = 62