Creational patterns with Java 8 lambdas

Datetime:2016-08-23 00:36:47          Topic: Java8           Share

Composition of abstract grids image via Shutterstock

In this article Michael Simons discusses how modern programming paradigms make software patterns not superfluous but easier to understand and less prone to error. He also shows how to make use of Java 8 Lambdas to create a very simple implementation of the factory pattern and a somewhat more complicated version of a builder pattern implementation.

Factory pattern

The abstract factory pattern provides a way to encapsulate a group of individual factories that have a common theme without specifying their concrete classes. In normal usage, a concrete implementation of the abstract factory is created and then the generic interface of the factory is used to create the concrete objects.

Very well known — and sometimes infamous — is the (abstract) factory pattern in Java land. Infamous because names tend to… grow sometimes. Poor Spring framework is often the target of a gazillion jokes just for having a class named SimpleBeanFactoryAwareAspectInstanceFactory , even if the name is actually well chosen: You’ll get a factory that produces instances of aspects by using another factory.

My example: Imagine a simple formula for computing the sum of natural numbers from 1 to n and represent them as a functional interface :

@FunctionalInterface
public interface Computation {
    public long sum1To(long n);
}

Our abstract factories should be able to deliver a naive, iterative implementation as well as the well-known Gaußsche Summenformel . You can implement such factories as a supplier of formulas or computations: Supplier<Computation> and that’s about all you’ll need to implement multiple factories supplying multiple different implementations of an abstract product:

import java.util.function.Supplier;

public class ComputationFactoryClient {

    public static void main(final String... a) {
        final Supplier<Computation> slowFactory = () -> n -> {
            long rv = 0L;
            for (long i = 1; i <= n; ++i) {
                rv += i;
            }
            return rv;
        };
        
        final Supplier<Computation> gaussFactory = () -> n -> (n * (n+1))/2;

        System.out.println(slowFactory.get().sum1To(100));
        System.out.println(gaussFactory.get().sum1To(100));
    }
}

Using the factory pattern this way will automatically bring a lot of flexibility to your code base without sacrificing readability.

However, the question of how to name those factories still stands.

Builder pattern

The builder pattern separates the construction of a complex object from its representation so that the same construction process can create different representations.

Builders are often used together with fluent APIs or small, domain specific languages (DSLs) to create immutable objects without “telescoping” constructors (a telescoping constructor occurs when the increase of object constructor parameter combination leads to an exponential list of overloaded constructors).

The following is an example from Spring Security configuration:

http
    .httpBasic()
        .and()
    .authorizeRequests()
        .antMatchers(
                "/api/system/env/java.(runtime|vm).*",
                "/api/system/metrics/**"
        ).permitAll()
        .antMatchers("/api/system/env/**").denyAll()
        .antMatchers("/**").permitAll()
        .and()
    .sessionManagement()
        .sessionCreationPolicy(STATELESS);

This is only part of it… Imaging a list of constructors for building all combinations of HTTP security objects.

The builder pattern is often used to configure things. Configuration often depends on a well-defined order of steps. The ideal implementation of a builder for me consists of a readable API, respecting the order of steps and resulting in an immutable object. Also, the builder used should be used only for one purpose.

My example: Configuration of a sandwich. The example isn’t new; Marco Castigliego already used it in 2012 to present his Step Builder pattern, but as I often wonder in my discussions with my wife whether the meat belongs below or on top of the cheese, it’s still relevant.

The following object is to be configured:

import java.util.List;

public class Sandwich {
    private final String bread;

    private final String meat;
    
    private final String cheese;

    private final List<String> vegetables;
    
    public String getBread() {
        return bread;
    }
   
    public String getMeat() {
        return meat;
    }
    
    public String getCheese() {
        return cheese;
    }
    
    public List<String> getVegetables() {
        return vegetables;
    }
}

I will skip custom types for bread and meat for brevity. The sandwich should be made using the following steps:

public static interface ChooseBreadStep {
    public ChooseMeatStep withMeat(final String meat);

    public AddVeggiesStep vegan();
}

public static interface ChooseMeatStep {
    public ChooseCheeseStep withCheese(final String cheese);

    public AddVeggiesStep noCheese();
}

public static interface ChooseCheeseStep {
    public AddVeggiesStep addVeggie(final String vegetable);

    public CloseStep noVeggies();
}

public static interface AddVeggiesStep {
    public AddVeggiesStep addVeggie(final String vegetable);

    public CloseStep close();
}

public static interface CloseStep {
    public Sandwich create();
}

After choosing the bread, the client can choose either a meat or a vegan sandwich. The vegan sandwich certainly skips the cheese as well, but uses veggies just like the meat sandwich. If you don’t like veggies, fine, skip them too.

The builder itself looks like this:

private static class Builder implements ChooseBreadStep, ChooseMeatStep, ChooseCheeseStep, AddVeggiesStep, CloseStep {
    final String bread;

    String meat;

    String cheese;
    
    final List<String> vegetables = new ArrayList<>();
    
    Builder(String bread) {
        this.bread = bread;
    }
    
    @Override
    public ChooseMeatStep withMeat(String meat) {
        this.meat = meat;
        return this;
    }
    
    @Override
    public AddVeggiesStep vegan() {
        return this;
    }
    
    @Override
    public ChooseCheeseStep withCheese(String cheese) {
        this.cheese = cheese;
        return this;
    }
    
    @Override
    public AddVeggiesStep noCheese() {
        return this;
    }
    
    @Override
    public AddVeggiesStep addVeggie(String vegetable) {
        this.vegetables.add(vegetable);
        return this;
    }
    
    @Override
    public CloseStep noVeggies() {
        return this;
    }
    
    @Override
    public CloseStep close() {
        return this;
    }
        
    @Override
    public Sandwich create() {
        return new Sandwich(this);
    }
}

Instantiating the sandwich through a private constructor in the sandwich class:

private Sandwich(Builder builder) {
        this.bread = builder.bread;
        this.meat = builder.meat;
        this.cheese = builder.cheese;
        this.vegetables = Collections.unmodifiableList(builder.vegetables);
    }

I prefer passing the builder to the object being build instead of using an empty private constructor.

No Java 8 so far. But wait, the builder wasn’t initialized up until now. This will be done with a static method on the class itself. The method will take all obligatory parameters as well:

public static Sandwich make(String bread, Function<ChooseBreadStep, CloseStep> configuration) {
    return configuration.andThen(CloseStep::create).apply(new Builder(bread));
}

Have a look at the second parameter: It’s a function mapping the ChooseBreadStep onto the CloseStep . By using a function (or, if you don’t use steps, a Consumer will be fine, too) a client cannot use the builder outside the context of actually creating an object. The builder has no public constructor and furthermore, it will not be reusable after the block ends.

Usage than looks like this:

public static void main(final String...a) {        
    Sandwich.make("white", cfg -> cfg
            .withMeat("parma")
            .withCheese("cheedar")
            .addVeggie("salad")
            .close()
    );
    Sandwich.make("brown", cfg -> cfg
            .withMeat("salami")
            .noCheese()
            .close());
    Sandwich.make("spelt", cfg -> cfg
            .vegan()
            .addVeggie("salad")
            .addVeggie("gherkins")
            .addVeggie("tomatoes")
            .close()
    );
}

In this case you can take advantage of Java 8 language feature to create an API that is less prone to error and which guides your client through the process of creating objects.

Summary

Functional programming makes a lot of patterns easier to understand and use. Lambdas or code blocks are much more than syntactic sugar for Java and are less distracting than plain Object-oriented programming.

For further reading I recommend Dr. Venkat Subramaniam’s talk “Designing with Lambda Expressions in Java” , which was a very inspiring source and also Mario Fusco’s Github Repository “From Gang Of Four Patterns to Lambdas”.





About List