Decorator Design Pattern using lambdas

With the advent of lambdas in Java we now have a new tool to better design our code. Of course the first step is using streams, method references and other neat features introduced in Java 8.

Going forward I think the next step is to revisit the well established Design Patterns and see them through the functional programming lenses. For this purpose I’ll take the Decorator Pattern and implement it using lambdas.

We’ll take an easy and delicious example of the Decorator Pattern: adding toppings to pizza. Here is the standard implementation as suggested by GoF:

First we have the interface that defines our component:

public interface Pizza {
    String bakePizza();
}

We have a concrete component:

public class BasicPizza implements Pizza {
    @Override
    public String bakePizza() {
        return "Basic Pizza";
    }
}

We decide that we have to decorate our component in different ways. We go with Decorator Pattern. This is the abstract decorator:

public abstract class PizzaDecorator implements Pizza {
    private final Pizza pizza;
    
    protected PizzaDecorator(Pizza pizza) {
        this.pizza = pizza;
    }

    @Override
    public String bakePizza() {
        return pizza.bakePizza();
    }
}

we provide some concrete decorators for the component:

public class ChickenTikkaPizza extends PizzaDecorator {
    protected ChickenTikkaPizza(Pizza pizza) {
        super(pizza);
    }

    @Override
    public String bakePizza() {
        return super.bakePizza() + " with chicken topping";
    }
}

public class ProsciuttoPizza extends PizzaDecorator {

    protected ProsciuttoPizza(Pizza pizza) {
        super(pizza);
    }

    @Override
    public String bakePizza() {
        return super.bakePizza() + " with prosciutto";
    }
}

and this is the way to use the new structure:

Pizza pizza = new ChickenTikkaPizza(new BasicPizza());
String finishedPizza = pizza.bakePizza();   //Basic Pizza with chicken topping

pizza = new ChickenTikkaPizza(new ProsciuttoPizza(new BasicPizza()));
finishedPizza  = pizza.bakePizza();  //Basic Pizza with prosciutto with chicken topping

we can see that this can get very messy, and it did get very messy if we think about how we handle buffered readers in java:

new DataInputStream(new BufferedInputStream(new FileInputStream(new File("myfile.txt"))))

of course, you can split that in multiple lines, but that won’t solve the messiness, it will just spread it.
Now lets see how we can do the same thing using lambdas.
We start with the same basic component objects:

public interface Pizza {
    String bakePizza();
}

public class BasicPizza implements Pizza {
    @Override
    public String bakePizza() {
        return "Basic Pizza";
    }
}

But now instead of declaring an abstract class that will provide the template for decorations, we will create the decorator that asks the user for functions that will decorate the component.

public class PizzaDecorator {
    private final Function<Pizza, Pizza> toppings;

    private PizzaDecorator(Function<Pizza, Pizza>... desiredToppings) {
        this.toppings = Stream.of(desiredToppings)
                .reduce(Function.identity(), Function::andThen);

    }

    
    public static String bakePizza(Pizza pizza, Function<Pizza, Pizza>... desiredToppings) {
        return new PizzaDecorator(desiredToppings).bakePizza(pizza);
    }

private String bakePizza(Pizza pizza) {
    return this.toppings.apply(pizza).bakePizza();
}

}

There is this line that constructs the chain of decorations to be applied:

Stream.of(desiredToppings).reduce(identity(), Function::andThen);

This line of code will take your decorations (which are of Function type) and chain them using andThen. This is the same as

(currentToppings, nextTopping) -> currentToppings.andThen(nextTopping)

and it sure that the functions are called subsequently in the order you provided.
Also Function.identity() is translated to elem -> elem lambda expression.

Ok, now where we’ll we define our decorations? You can add them as static methods in PizzaDecorator or even in the interface:

public interface Pizza {
    String bakePizza();

    static Pizza withChickenTikka(Pizza pizza) {
        return new Pizza() {
            @Override
            public String bakePizza() {
                return pizza.bakePizza() + " with chicken";
            }
        };
    }

    static Pizza withProsciutto(Pizza pizza) {
        return new Pizza() {
            @Override
            public String bakePizza() {
                return pizza.bakePizza() + " with prosciutto";
            }
        };
    }
}

And now, this is how this pattern gets to be used:

String finishedPizza = PizzaDecorator.bakePizza(new BasicPizza(),Pizza::withChickenTikka, Pizza::withProsciutto);

//And if you static import PizzaDecorator.bakePizza:

String finishedPizza  = bakePizza(new BasicPizza(),Pizza::withChickenTikka, Pizza::withProsciutto);

As you can see, the code got more clear and more concise, and we didn’t use inheritance to build our decorators.

This is just one of the many design pattern that can be improved using lambdas. There are more features that can be used to improve the rest of them like using partial application (currying) to implement Adapter Pattern.

I hope I got you thinking about adopting a more functional programming approach to your development style.

UPDATE: Here you can find a video walkthrough of this article, created by my friends from Webucator:

If you want to see more of their tutorials you can visit Webucator site

Bibliography:

The decorator example was inspired by Gang of Four – Decorate with Decorator Design Pattern article

The refactoring method was inspired by the following Devoxx 2015 talks (which I recommend watching as they treat the subject at large):
Design Pattern Reloaded by Remi Forax
Design Patterns in the Light of Lambda Expressions by Venkat Subramaniam

 

Java in 2015 – Major happenings

2015 was the year where Java the language, platform, ecosystem and community continue to dominate the software landscape, with only Javascript having a similar sized impact on the industry. In case you missed the highlights of 2015, here’s some of the major happenings that occurred.

Java 20 years old and still not dead yet!

Java turned 20 this year and swept back to the top of the Tiobe index in December 2015. Although the Tiobe index is hardly a 100% peer reviewed scientific methodology, it is seen as a pretty strong barometer for the health of a language/platform. So what the heck happened to boost Java so dramatically again?

Firstly, the release of Java 8 the previous year was adopted by mainstream Java enterprise shops. The additional functional capabilities of Lambdas combined with the new Streams and Collections framework breathed a new lease of life into the language. Although Java 8 is not as rich in its feature set as say Scala or Python it is seen as the steady workhorse that now has at least some feature parity with more aggressive languages. Enterprises love a stable platform and it’s unlikely that Java will be disappearing any time soon.

Secondly, Java has become a strong platform to use for infrastructure platforms/frameworks. Many popular NoSQL, datagrid solutions such as Apache Cassandra, Hazelcast are written in Java, again due to its stability and strong threading and networking support. CI tools such as Jenkins are widely adopted and of course business productivity tools such as Atlassian’s JIRA are again Java based.

Oracle guts its Java evangelism team

Oracle fired much of its Java evangelism team just before JavaOne which wasn’t the greatest PR move by the stewards of Java. Over the subsequent months it became clearer that this wasn’t a step by Oracle to reduce its engineering efforts into Java but there were nervous times for much of the community as they feared the worst. A salient reminder that big corporations don’t always get their left hand talking to their right!

Java 9 delay announced

In the “We’re not really surprised” bucket came the announcement the Java 9 will be delayed until March 2017 in order to ensure that the new modularisation system will not break the millions of Java applications running out there today.

Although the technical work of Jigsaw is progressing nicely, the entire ecosystem will need to test on the new system. The Quality group in OpenJDK is leading this effort. I highly recommend you contact them to be part of the early access and feedback loop.

OpenJDK supports further mobile platforms

The creation of the OpenJDK mobile project came as a surprise to many and although it doesn’t represent a change in Oracle’s business direction it was a wlecome release of code to enable Java on ARM, Android and iOS platforms. There’s much technical work to do but it will be interesting to watch if the software community at large picks up on this new support and tries Java out as a language for the iOS and Android platforms in 2016 and beyond. There is a possibility that OpenFX (JavaFX) combined with Java mobile on iOS or Android may entice a slew of developers to this ‘new’ platform.

Was I right about 2015?

It’s always fun to look at past predictions, let’s see how I did!

  1. I expected 2015 to be a little bit quieter. Well I clearly got that wrong! Despite no major releases for ME, SE or EE, the excitement of celebrating 20 years of Java and a surge of new developers using Java 8 meant 2015 was busier than ever.
  2. Embracing Javascript for the front end. This trend continues and stacks such as JHipster show the new love affair that Java developers have with Javascript.
  3. Devops toolchains to the fore. Docker continues to steamroll ahead in terms of popularity and Java developers are especially starting to use Docker in test environments to avoid polluting environments with variations in Java runtimes, web servers, data stores etc.
  4. IoT and Java to be a thing. Nope, not yet! Perhaps in 2016 with the new Mobile Java project in OpenJDK and further refinement of Java ME, we may start to see serious inroads.

I’m not going to make any predictions for 2016 as I clearly need to stick to my day job 🙂

One final important note. Project Jigsaw is the modularisation story for Java 9 that will massively impact tool vendors and day to day developers alike. The community at large needs your help to help test out early builds of Java 9 and to help OpenJDK developers and tool vendors ensure that IDEs, build tools and applications are ready for this important change. You can join us in the Adoption Group at OpenJDK. I hope everyone has a great holiday break – I look forward to seeing the Twitter feeds and the GitHub commits flying around in 2016 :-).

Cheers,
Martijn (CEO – jClarity, Java Champion & Diabolical Developer)

This post is part of the Java Advent Calendar and is licensed under the Creative Commons 3.0 Attribution license. If you like it, please spread the word by sharing, tweeting, FB, G+ and so on!