What Is Decorator Pattern?

Decorator design pattern is a pattern which modifies the functionality of an object. In other words it gives different flavours to an object without using inheritance. You might think why not use inheritance if you are talking about flavours? Well, yes these are flavours but the permutation and combination of these flavours can be many and in that case it doesn’t make sense to create a class for each combination.

Lets say you have 6 factors that can change the characteristics of your object, in that case you will have factorial of 6 which is, 6! = 720, so there can be 720 objects with different characteristics.

When to use it?

This pattern can be used when you have a requirement that you have to add characteristics to an object at runtime. And the factors that can affect the object’s characteristics are many.

Video


Lets Understand With An Example

Problem Statement - In a flight while booking a main cabin seat, you can choose facilities like WiFi, Live TV, Head Phones etc. At the end you should show the price of the seat after including the individual price of each facility that user has chosen. For instance

Main cabin seat - $ 500.0 WiFi: $ 10 Live TV: $ 8.0 Head Phones: $ 5.0

If use choses WiFi and Head Phones with main cabin seat then total cost would be 500.0 + 10.0 + 5.0 = $ 515.0

Similarly there can be multiple combination of facilities a user can choose.

Design

Crepe

As you can see in the above image that we have a FlightSeat Interface and MainCabinSeat implements FlightSeat. We have an abstract class FlightSeatDecorator which holds an instance of FlightSeat. And we have 3 facilities (decorators) which extends the FlightSeatDecorator class.

Implementation

Above is the github link to decorator pattern implementation. Still we will discuss the implementation of some important classes.

The FlightSeat interface has only two methods one gives the chosen facilities with the seat and other tells the cost of the seat with facilities.

package decorator_pattern;

public interface FlightSeat {

    String getFacilities();

    Double getCost();

}

The FlightSeatDecorator has an instance of FlightSeat and also has both the methods.

package decorator_pattern.decorator;

import decorator_pattern.FlightSeat;

public abstract class FlightSeatDecorator implements FlightSeat {
    protected FlightSeat flightSeat;

    public FlightSeatDecorator(FlightSeat flightSeat) {
        this.flightSeat = flightSeat;
    }

    public abstract String getFacilities();

    public abstract Double getCost();
}

MainCabinSeat implements the FlightSeat and both its methods.

package decorator_pattern;

public class MainCabinSeat implements FlightSeat {
    @Override
    public String getFacilities() {
        return "Main Cabin Seat";
    }

    @Override
    public Double getCost() {
        return 500.0;
    }
}

WiFi decorator extends the FlightSeatDecorator and implements both the methods which are there in the decorator. It has its own cost.

package decorator_pattern.decorator;

import decorator_pattern.FlightSeat;

public class WiFi extends FlightSeatDecorator {
    public WiFi(FlightSeat flightSeat) {
        super(flightSeat);
    }

    @Override
    public String getFacilities() {
        return this.flightSeat.getFacilities() + "\nWiFi";
    }

    @Override
    public Double getCost() {
        return this.flightSeat.getCost() + 10.0;
    }
}

Below is the main class which shows how we can use the facilities with the seat and get the cost.

package decorator_pattern;

import decorator_pattern.decorator.HeadPhone;
import decorator_pattern.decorator.LiveTV;
import decorator_pattern.decorator.WiFi;

public class Test {
    public static void main(String[] args) {
        FlightSeat mainCabinSeat = new WiFi(new HeadPhone(new LiveTV(new MainCabinSeat())));

        System.out.println("Chosen Facilities for your seat:");
        System.out.println(mainCabinSeat.getFacilities());
        System.out.println("Total Cost:" + mainCabinSeat.getCost());
    }
}

If you want to see the implementation of all the classes then please visit the github link. And if you have any feedback, suggestion, concern or opinion please leave a comment below.