Lambda in the circle with code surrounding it

Functional Java – Decorator pattern. Classic and functional approach 2


Decorator is a structural design pattern. It is used to modify functionality of a specific instance of an object at runtime. Modification of the behavior does not affect other instances of the same class. Decorator also known as Wrapper is a helpful tool in every programmer’s toolbox. Unfortunately Java programmers often under-use decorator pattern.

Ugly decorator code

Before Java 8 using decorator pattern meant that you needed to pass instance that you wanted to decorate as a constructor argument. The more decorated particular instance was, the more unreadable the code became. Everyone who has ever used Java’s IO knows exactly what I am talking about.

Most concrete implementations of abstract classes java.io.Reader, java.io.Writer, java.io.InputStream and java.io.OutputStream have a constructor that takes an instance of that abstract class. So if you see the code like the one below  you might get discouraged and decide not to use decorator pattern ever again.

new PushbackReader( new BufferedReader( new FileReader( new File("data.csv"))));

So many brackets. So little time.

Classic decorator pattern

Let’s say that you work for a boat factory. Additional accessories can be installed on the boat per customer request.

First thing you need is a component that will represent your product. This can be an interface or an abstract class that defines the methods you want to implement.

public interface Boat {
    public void createBoat();
}

You will also need concrete implementation of that component. BareBoat represents the most basic version of your product with no additional accessories installed.

public class BareBoat implements Boat {

    @Override
    public void createBoat() {
        System.out.println("Creating a boat");
    }
}

Declare a decorator. Notice the protected reference to the component. This way the reference will be visible to it’s children. Decorator also implements the component.

public class BoatDecorator implements Boat {

    protected Boat boat;

    public BoatDecorator(Boat boat) {
        this.boat = boat;
    }

    @Override
    public void createBoat() {
        this.boat.createBoat();
    }
}

Concrete decorators customize component’s behavior. They represent boat accessories that are available to your clients. At runtime you can create a boat and decorate it with paddles, sails and an engine or any combination of aforementioned accessories.

public class PaddleBoat extends BoatDecorator {

    public PaddleBoat(Boat boat) {
        super(boat);
    }

    @Override
    public void createBoat() {
        boat.createBoat();
        System.out.println("Adding paddles to the boat");
    }
}

public class SailBoat extends BoatDecorator {

    public SailBoat(Boat boat) {
        super(boat);
    }

    @Override
    public void createBoat() {
        boat.createBoat();
        System.out.println("Adding sails to the boat");
    }
}

public class MotorBoat extends BoatDecorator {

    public MotorBoat(Boat boat) {
        super(boat);
    }

    @Override
    public void createBoat() {
        boat.createBoat();
        System.out.println("Adding engine to the boat");
    }
}

Creating a boat and adding all available accessories to it could look something like this

Boat b = new MotorBoat( new SailBoat( new PaddleBoat( new BareBoat())));
b.createBoat();
Creating a boat
Adding paddles to the boat
Adding sails to the boat
Adding engine to the boat

Functional decorator

There is a functional way to inject behavior to a specific instance at runtime without affecting other instances of the same class. It improves code readability but it also has some limitations comparing to the classic approach.

You can achieve the same result with some help from Function functional interface introduced in Java 8. First we are going to substitute concrete decorators with default methods returning a component.

public interface Boat {

    public void createBoat();

    default public Boat addPaddles() {
        System.out.println("Adding paddles to the boat");
        return this;
    }

    default public Boat addSails() {
        System.out.println("Adding sails to the boat");
        return this;
    }

    default public Boat addEngine() {
        System.out.println("Adding sails to the boat");
        return this;
    }
}

Instead of creating multiple concrete decorators and passing decorated object as constructor argument you can pass an array (vararg) of Function<T,R>. Each member of an array represents the process of adding one of the boat accessories.

public class BareBoat implements Boat {

    private Function<Boat,Boat> acc;

    public BareBoat(Function<Boat,Boat>... accessories) {
        acc = Stream.of(accessories).reduce(Function.identity(), Function::andThen);
    }

    @Override
    public void createBoat() {
        System.out.println("Creating a boat");
        acc.apply(this);
    }
}

Let’s discuss what is happening in the constructor of modified BareBoat. It takes an array of Function as argument. Each of those functions takes Boat as input parameter. Function does something or perhaps does nothing and then returns the Boat to the client. A Function that takes an argument, does nothing and returns it is called an identity function.

reduce() method is used to perform a reduction on elements of the stream. It takes two arguments. First one is an identity value which in our case is aforementioned identity function. Second argument is method reference to Function::andThen. andThen() composes two functions and turns them into one. As a result stream of functions is reduced to just one function and saved as acc property.

createBoat() applies the result of the reduction to current object and in consequence runs all the functions that were passed as constructor argument to BareBoat.

Finally we can create another boat with all accessories offered by the factory. This time we’ll do it the functional way.

Boat b = new BareBoat(Boat::addPaddles, Boat::addSails, Boat::addEngine);
b.createBoat();
Creating a boat
Adding paddles to the boat 
Adding sails to the boat 
Adding engine to the boat

Pros and cons

As you can see functional code is much more concise and readable. However there are some drawbacks of functional decorator approach that you should be aware of.

In classic approach concrete decorators are classes so you can decorate your objects with additional class properties. If you look at FileInputStream class which extends InputStream you’ll notice that the decorated object gains such properties as FileDescriptor and path to a referenced file.

Decorating objects with properties is not as easy with concrete decorators represented as functions. You could add more properties to concrete implementation of the component (BareBoat) but that could potentially break single responsibility principle.

You need to decide for yourself if functional decorator is valid for your use case.

Thanks for reading ! Please
  •  
  •  
  • 3
  •  
  •  
  •  
  •  
  •  

Leave a comment

Your email address will not be published. Required fields are marked *

2 thoughts on “Functional Java – Decorator pattern. Classic and functional approach

  • Jayesh Pawar

    Hey

    Amongst, most of the decorator pattern on the web. I think, you have the best material. I really liked it.
    I do not comment on any blog but yours is unique.