Think functional: Advanced builder pattern using lambda

<a href=”http://www.freepik.com/free-vector/it-s-lunchtime-for-this-worker_911190.htm">Designed by Freepik</a>

Builder pattern comes handy when a large complex object is to be built. Specially when it can be built in multiple combinations. There is one reason for which I have always hated builder pattern is that you need to add a new method to set a value for every member variable in the class. Whenever a new variable gets added, a new method need to be introduced in builder. Many times developers would just copy an existing assignment method and would just rename it without modifying the assignment expression inside it. For very long number of member variables, builders become very huge and it gets worse if it’s a composite object of many small objects. Builders become more complex and less readable as objects become complex.

Groovy has a nice way of constructing objects using ‘with’ method.

sample.with {
username = 'mrhaki'
email = 'email@host.com'
addLabel 'Groovy'
addLabel 'Java'
}

While looking at the ‘with’ method I started thinking, why can’t we have similar builder in Java 8 ?

Let’s understand the builder pattern first.

Introduction

What is builder pattern and why is it needed?

Lets assume we want to build an object of a Person class.

public class Person
{
private final String firstName;
private final String lastName;

public Person(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}

}

How do you create a person object? Simple

new Person("John", "Doe");

But some persons can have middle name too. Not a problem just add another constructor.

public class Person {

private final String firstName;
private final String lastName;
private final String middleName;

public Person(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
this.middleName = null;
}

public Person(String firstName, String lastName, String middleName) {
this.firstName = firstName;
this.lastName = lastName;
this.middleName = middleName;
}
}

A person can have an optional salutation as well. Ok. Lets try adding another constructor.

public class Person {

private final String firstName;
private final String lastName;
private final String middleName;
private final String salutation;

public Person(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
this.middleName = null;
salutation = null;
}

public Person(String firstName, String lastName,
String middleName) {
this.firstName = firstName;
this.lastName = lastName;
this.middleName = middleName;
salutation = null;
}

public Person(String firstName, String lastName,
String middleName, String salutation) {
this.firstName = firstName;
this.lastName = lastName;
this.middleName = middleName;
this.salutation = salutation;
}
}

Notice how we have to assign a null value to optional parameters in each constructor, since all the member variables are final and should be initialised in a constructor. Well this can be written better using a chain of constructors. i.e. One constructor calling the other one where null is passed for optional parameters.

The person class can be re-written using chain of constructors.

public class Person {

private final String firstName;
private final String lastName;
private final String middleName;
private final String salutation;

public Person(String firstName, String lastName) {
new Person(firstName, lastName, null);
}

public Person(String firstName, String lastName,
String middleName) {
new Person(firstName, lastName, middleName, null);
}

public Person(String firstName, String lastName,
String middleName, String salutation) {
this.firstName = firstName;
this.lastName = lastName;
this.middleName = middleName;
this.salutation = salutation;
}
}

This is fine when number of member variables and constructors are limited.

What if our person class looks like this with many optional member variables.

public class Person
{
private final String salutation;
private final String firstName;
private final String middleName;
private final String lastName;
private final String suffix;
private final Address address;
private final boolean isFemale;
private final boolean isEmployed;
private final boolean isHomewOwner;


public Person(String salutation, String firstName, String middleName, String lastName, String suffix, Address address, boolean isFemale, boolean isEmployed, boolean isHomewOwner) {
this.salutation = salutation;
this.firstName = firstName;
this.middleName = middleName;
this.lastName = lastName;
this.suffix = suffix;
this.address = address;
this.isFemale = isFemale;
this.isEmployed = isEmployed;
this.isHomewOwner = isHomewOwner;
}
}

Adding a new member variable adds a new possible way of constructing the person object. Can you imagine the number of constructors we will have to write to be able to cater all those combinations. That’s when builder pattern comes to rescue.

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

In our example the person class is cluttered with the construction logic i.e. chain of constructors. Let’s separate the object construction.

The old school one

Lets write a traditional style builder to build a person object.

I have used intellij to generate the builder from the constructor using:

Refactor > Replace Constructor with builder

public class PersonBuilder {
private String salutation;
private String firstName;
private String middleName;
private String lastName;
private String suffix;
private Address address;
private boolean isFemale;
private boolean isEmployed;
private boolean isHomewOwner;

public PersonBuilder withSalutation(String salutation) {
this.salutation = salutation;
return this;
}

public PersonBuilder withFirstName(String firstName) {
this.firstName = firstName;
return this;
}

public PersonBuilder withMiddleName(String middleName) {
this.middleName = middleName;
return this;
}

public PersonBuilder withLastName(String lastName) {
this.lastName = lastName;
return this;
}

public PersonBuilder withSuffix(String suffix) {
this.suffix = suffix;
return this;
}

public PersonBuilder withAddress(Address address) {
this.address = address;
return this;
}

public PersonBuilder withIsFemale(boolean isFemale) {
this.isFemale = isFemale;
return this;
}

public PersonBuilder withIsEmployed(boolean isEmployed) {
this.isEmployed = isEmployed;
return this;
}

public PersonBuilder withIsHomewOwner(boolean isHomewOwner) {
this.isHomewOwner = isHomewOwner;
return this;
}

public Person createPerson() {
return new Person(salutation, firstName, middleName, lastName, suffix, address, isFemale, isEmployed, isHomewOwner);
}

Using this builder

Person person = new PersonBuilder()
.withSalutation("Mr.")
.withFirstName("John")
.withLastName("Doe")
.withIsFemale(false)
.withAddress(new AddressBuilder()
.withCity("Pune")
.withState("MH")
.withStreet("MG Road")
.withPin("411001")
.createAddress())
.createPerson();

The advanced way

public class PersonBuilder {
public String salutation;
public String firstName;
public String middleName;
public String lastName;
public String suffix;
public Address address;
public boolean isFemale;
public boolean isEmployed;
public boolean isHomewOwner;

public PersonBuilder with(
Consumer<PersonBuilder> builderFunction) {
builderFunction.accept(this);
return this;
}


public Person createPerson() {
return new Person(salutation, firstName, middleName,
lastName, suffix, address, isFemale,
isEmployed, isHomewOwner);
}
}

Is that all we need? Yes. Let’s understand the with method.

‘with’ method takes a function of type Consumer. Consumer is a functional interface provided by Java 8, which takes single argument and returns no result. In this case it accepts an object of type person builder which is passed to accept method. Which means that the instance of the builder would be accessible in the lambda expression and we can do whatever we want.

Let look at how the builder is used

Person person = new PersonBuilder()
.with(personBuilder -> {
personBuilder.salutation = "Mr.";
personBuilder.firstName = "John";
personBuilder.lastName = "Doe";
personBuilder.isFemale = false;
})
.createPerson();

Isn’t it a cleaner way of constructing object? All the assignment statements are nicely encapsulated in a lambda expression. We can also do the chaining of with method.

Person person = new PersonBuilder()
.with(personBuilder -> {
personBuilder.salutation = "Mr.";
personBuilder.firstName = "John";
personBuilder.lastName = "Doe";
personBuilder.isFemale = false;
})
.with(personBuilder -> personBuilder.isHomewOwner = true)

But still we have to write personBuilder.fieldName for every assignment. Wouldn’t it be great if we could get rid of personBuilder variable name in lambda expression. Unfortunately Java 8 does not provide a default parameter name for lambda expression.

We can get around this problem by renaming our variable to ‘$’.

Person person = new PersonBuilder()
.with($ -> {
$.salutation = "Mr.";
$.firstName = "John";
$.lastName = "Doe";
$.isFemale = false;
})
.with($ -> $.isHomewOwner = true)

Wow ! Not that looks great. Very much like a functional programming language.

It goes well with composite objects as well. The construction of nested object can be well encapsulated in a with clause.

Person person = new PersonBuilder()
.with($ -> {
$.salutation = "Mr.";
$.firstName = "John";
$.lastName = "Doe";
$.isFemale = false;
})
.with($ -> $.isHomewOwner = true)
.with($ -> {
$.address =
new PersonBuilder.AddressBuilder()
.with($_address -> {
$_address.city = "Pune";
$_address.state = "MH";
$_address.pin = "411001";
}).createAddress();
})
.createPerson();

Here address is a nested object inside person. Notice the variable name for addressBuilder is $_address. Which clearly reveals its intent.

We can encapsulate all the assignments in a single with block as well.

Person person = new PersonBuilder()
.with($ -> {
$.salutation = "Mr.";
$.firstName = "John";
$.lastName = "Doe";
$.isFemale = false;
$.isHomewOwner = true;
$.address =
new PersonBuilder.AddressBuilder()
.with($_address -> {
$_address.city = "Pune";
$_address.state = "MH";
$_address.pin = "411001";
}).createAddress();
})
.createPerson();

The old style of builders look noisy, are difficult to read and maintain. And it gets worse if the object is composed of multiple small objects, writing an old style builder is cumbersome.

There is a downside of the builder using lambda expression. Since the assignments are done in lambda expression the member variables of the builder must be public. Hey! but whats the point of keeping them private, since we can nicely encapsulate the assignment statements in a chain of lambda expressions. And that’s the whole purpose of builder, making object construction easy and readable. Also note that to support a new member variable, we just have to put that variable in the builder and unlike old school builder we don’t have to introduce a new method for that.

That being said, advanced way of creating builders could save developers a lot of time and trouble. It can also be used to generate a test data for huge complex objects.

This is best I could achieve using lambda expressions and am still trying to make it better. Please let me know the feedback and suggestions or if you have a way of making it better.

Also read: Understanding Functor and Monad