Fluent Builder Pattern with a real-world example

Amit Kumar
Xebia Engineering Blog
7 min readOct 31, 2019
Photo by Won Young Park on Unsplash

As a fresher, I have been trying to learn new aspects of programming each day and I always strive to go into the depth of any topic so that I can use it efficiently in my project. A few days back, I learnt about the classical builder pattern which is a preferred way to create a complex object with many optional parameters. While going through this topic, I came across the term “fluent builder pattern”. Initially, I thought it is just another name of classical builder pattern, but then I realized that it was only my assumption. When I started to explore more about it, I found out it is significantly different and I can use it to build real-world APIs. In this blog, we will try and understand what classical builder pattern is, how it is used with the help of a real-world example. Further, we will discuss the limitations associated with it and how the fluent builder pattern helps to overcome those limitations.

For the sake of simplicity, we will call fluent builder pattern as FBP and classical builder pattern as CBP. So let’s begin.

Before we move further first let’s take a quick look at what is FBP and CBP.

So, CBP allows us to write readable, understandable code to set up complex objects. E.g Think of a search query for a book, the search query can any number of attributes from a given pool of attributes like title, author name, ISBN, date, publication, etc. So, in this case, we form an object using CBP as it gives you the flexibility to form a search query object in an easy way.

On the other hand, FBP is a style of coding which forces the developer to create the object in sequence by calling each setter method one after another until all required attributes are set. E.g Use it when you need to perform a task with certain attributes step by step, any mismatch of step will result in an error. E.g Think of a metro card recharge on PayTm.

After wetting our hands in the definition of both patterns, it’s time to understand them using a real-world example of PayTM recharge of Metro card. Those who are not aware of this metro card recharge using PayTm: PayTm is an app that provides service to recharge Metro card by entering your card number, amount and you can apply promoCode to get exciting offers on recharge.

We will solve the above-mentioned example first using CBP and then we will discuss why it is not the best approach and then we will see how FBP can solve this issue.

Let’s look at the CBP code example to understand how it can be solved using it.

class MetroCardRechargeRequest {
private long cardNumber;
private double amount;
private String promoCode;
private MetroCardRechargeRequest(Builder builder) {
cardNumber = builder.cardNumber;
amount = builder.amount;
promoCode = builder.promoCode;
} public static final class Builder {
private long cardNumber;
private double amount;
private String promoCode;
Builder() {
}
Builder setCardNumber(long val) {
cardNumber = val;
return this;
}
public Builder setAmount(double val) {
amount = val;
return this;
}
Builder setPromoCode(String val) {
promoCode = val;
return this;
}
MetroCardRechargeRequest build() {
return new MetroCardRechargeRequest( this );
}
}
}

Here if you see the above code, there is cardNumber, amount, promoCode fields which are required when we go for recharge. Although promoCode is optional but amount and cardNumber are mandatory fields. So process to do Metro card recharge is as follows:

  • Enter the card number
  • Enter the amount
  • Apply promoCode if you want

This is the order and required attributes we need to complete our recharge through PayTm and we can do it easily using the above pattern as given below:

MetroCardRechargeRequest recharge=new          MetroCardRechargeRequest.Builder()
.setCardNumber( 123456 )
.setCardNumber( 500 )
.setPromoCode( “MONTHLY100” )
.build();

But wait? What is wrong with this approach? Think!

Here we are dealing with only three attributes so it seems easy. But what if the number of attributes is more than 8 or 11? Will you be able to remember all the steps in the correct order in that case? Certainly not!

Developer can make mistake while setting attributes in proper order.

Fluent Builder in the Real World

Think of the formation of a SQL query in java where we need to provide all attributes in proper order and any mismatch will result in an error. We can’t just rely on CBP while solving this kind of problem. An example of SQL query using JOOQ is:

  final Author a = AUTHOR.as(“a”);  create.selectFrom(a)
.where(exists(selectOne()
.from(BOOK)
.where(BOOK.STATUS.equal(BOOK_STATUS.SOLD_OUT))
.and(BOOK.AUTHOR_ID.equal(a.ID))));

Just see the above code snippet, if you know SQL then you can see the above query is built in an order which can’t be changed and all attributes are in order and any mismatch will result in the wrong query. So here we can’t just solve these kinds of problems with CBP. We need a more reliable way to solve these problems.

So until now, we have seen that CBP is an approach we have used to form a complex object with many optional parameters. But we can’t rely on it where we need to apply attributes in an order as we have seen above on SQL query example.

To deal with such problems we look for FBP which solve these kinds of problems. Let us solve the Metro card recharge problem using FBP. We will use fluent interface to code apply FBP In our code. First, let’s see what is the fluent interface.

In software engineering, a fluent interface (as first coined by Eric Evans and Martin Fowler) is a method for designing object-oriented APIs based extensively on method chaining with the goal of making the readability of the source code close to that of ordinary written prose, essentially creating a domain-specific language within the interface. Wikipedia

In simple language:

For achieving fluent builder, we are going to create an interface chain where each interface method will return the next interface type.

So basically what FBP does that it uses interfaces that have methods and each method within an interface return next interface type which is the next step and then method in this interface return next interface type and so on. It makes more sense when we see it in code. Some area in JAVA where it is used extensively is as follows:

  • JOOQ
  • Stream API
  • Mockito

Enough talking, let’s see FBP in action:

class MetroCardRechargeRequest {
private long cardNumber;
private double amount;
private String promoCode;
private MetroCardRechargeRequest(long cardNumber, double amount, String promoCode) {
this.cardNumber = cardNumber;
this.amount = amount;
this.promoCode = promoCode;
}
public interface MetroIcon {
SmartCardNumber tapOnMetroIcon();
}
public interface SmartCardNumber {
SmartCardAmount addCardNumber(long number);
}
public interface SmartCardAmount {
Proceed addAmount(double amount);
}
public interface Proceed {
ProceedToPay proceed();
}
public interface ProceedToPay {
Pay applyPromoCode(String promoCode);
Pay proceedToPay();
}
public interface Pay {
SmartCardBuild payAmount();
}
public interface SmartCardBuild {
MetroCardRechargeRequest build();
}
public static class MetroCardRechargeRequestBuilder implements
MetroIcon, SmartCardNumber, SmartCardAmount, Proceed, ProceedToPay, Pay, SmartCardBuild {
private long cardNumber;
private double amount;
private String promoCode;
MetroCardRechargeRequestBuilder() {
}
@Override
public SmartCardNumber tapOnMetroIcon() {
return this;
}
@Override
public SmartCardAmount addCardNumber(long number) {
this.cardNumber = number;
return this;
}
@Override
public Proceed addAmount(double amount) {
this.amount = amount;
return this;
}
@Override
public ProceedToPay proceed() {
return this;
}
@Override
public Pay applyPromoCode(String promoCode) {
this.promoCode = promoCode;
return this;
}
@Override
public Pay proceedToPay() {
return this;
}
@Override
public SmartCardBuild payAmount() {
return this;
}
@Override
public MetroCardRechargeRequest build() {
return new MetroCardRechargeRequest( cardNumber, amount, promoCode );
}
}
}

Take some time and go through the above code and figure out what is happening here. We are solving the same problem using FBP this time.

You can see above that there are many interfaces out there and they have methods and each method returns a type of interface which is the next executing step and so on. MetroCardRechargeRequestBuilder implements all the interfaces, see the return type of each method. Here we can deduce one thing when we begin our process of recharge by calling tapOnMetroIcon() we have no option other than to call to addCardNumber(number) and so on. Now, look at the definition of FBP mentioned above which says developers are forced to call each setter method in proper sequence and hence there is no scope of error even if there is any number of attributes. It gives you a more reliable way to solve your problem if it requires a step by step execution of stuff.

Following code shows how to recharge card using FBP:

 MetroCardRechargeRequest recharge = new MetroCardRechargeRequest
.MetroCardRechargeRequestBuilder()
.tapOnMetroIcon()
.addCardNumber( 123 )
.addAmount( 256 )
.proceed()
.applyPromoCode( “Monthly52” )
.payAmount()
.build();

Here you just cannot skip any step and you have to follow the proper steps to get your things done. One thing to note if you see ProccedToPay interface then you will see two methods are there as I say applyPromoCode(promoCode) is optional, you can skip it if you want. To get more feel about it, I would suggest to code what I have done above and you will see the magic when you finish it.

So, we have discussed all aspects of both CBP and FBP. Use CBP where you want to create a complex object with many optional parameters. Use FBP where you are required to solve a problem in a proper order where each step is mandatory although some steps may be optional. Remember, creating a builder involves lots of boilerplate code, so use it wisely.

The sample code for this project can be found on Github.

--

--

Amit Kumar
Xebia Engineering Blog

Spring, Spring boot, Java developer, code quality, learning , writing and sharing.