Design Patterns - Decorator Pattern

decoraator-pattern-russian-dolls

Decorator Pattern is a design pattern that allows behavior to be added to an individual objects without affecting the behavior of other objects from the same class.

Intent

According to Gang of Four, the intent of Decorator Patterns is to:

Attach additional responsibility to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality.

Problem

You want to add behavior or state to individual objects at run-time.

Solution

Allows for extending the functionality of an object without sub-classing for extending functionality.

Participants

  • Component Interface - The interface or abstract defining the function added to it by the Decorator.
  • Concrete Component - Basic implementation of the Component Interface.
  • Decorator - Decorator class implements the Component Interface and it has a HAS-A relationship with the Component Interface. In other words, Decorator class wraps the Component class.
  • Concrete Decorator - Extends the base decorator functionality and modifying the component behavior accordingly.

Implementation

Create an abstract class that represents both the original class and the new functions to be added to the class. In the decorators, place the new function class before or after the trailing class to get the correct order.

decorator-uml

Example

decoraator-pattern-russian-dolls

Component Interface

Car.java

package com.art.designpatterns.decorator;

/*
Component Interface - Defines Interface for all the Classes to Use
 */
public interface Car {
    void assemble();
}

Component Implementation HondaCar.java

package com.art.designpatterns.decorator;

/**
 * Concrete Component - Class having function added to it
 */
public class HondaCar implements Car{

    @Override
    public void assemble() {
        System.out.println("Assembling Honda Car");
    }
}

Decorator CarDecorator.java

package com.art.designpatterns.decorator;

/**
 * Decorator Class
 */
public class CarDecorator implements Car{

    protected  Car car;

    public CarDecorator(Car car) {
        this.car = car;
    }

    @Override
    public void assemble() {
        this.car.assemble();
    }
}

Concrete Decorators

LuxuryFeature.java

package com.art.designpatterns.decorator;

/**
 * Concrete Decorator with Added Behaviour
 */
public class LuxuryFeature extends CarDecorator{

    public LuxuryFeature(Car car) {
        super(car);
    }

    @Override
    public void assemble() {
        super.assemble();
        System.out.println("Adding Features of Luxury Car");
    }
}

SportsFeature.java

package com.art.designpatterns.decorator;

/**
 * Concrete Decorator with Added Behaviour
 */
public class SportsFeature extends CarDecorator{

    public SportsFeature(Car car) {
        super(car);
    }

    @Override
    public void assemble() {
        super.assemble();
        System.out.println("Adding Features of Sports Car");
    }
}

Demo

package com.art.designpatterns.decorator;

public class DecoratorDesignPatternDemo {

  /**
   * Demo of Decorator Design pattern where Decorator's are added to Concrete Class
   * HondaCar is Concrete Component
   * LuxuryCar or SportsCar based on Abstract Decorator Class
   * @param args
   */
  public static void main(String[] args) {

    Car sportCar = buildSportsHondaCar();
    sportCar.assemble();

    Car luxuryCar = buildLuxuryHondaCar();
    luxuryCar.assemble();
  }

  private static Car buildSportsHondaCar() {
    Car baseCar1 = new HondaCar();
    Car sportCar = new SportsFeature(baseCar1);
    return sportCar;
  }

  private static Car buildLuxuryHondaCar() {
    Car baseCar2 = new HondaCar();
    Car luxuryCar = new LuxuryFeature(baseCar2);
    return luxuryCar;
  }

}

Summary

  • It is also known as Wrapper Pattern as it allows behavior to be added to an individual objects either statically or dynamically without affecting the behavior of other objects from the same class.

  • Decorator pattern allows to create a chain of objects that starts with the Decorator Object - the objects responsible for the new function and ends with the concrete Component.

  • Adheres to Open Close Principle

Classes should be open for extension, but closed for modification.