Introduction to the Fluent Builder Pattern
Learn more about the fluent builder pattern in the post below.
Join the DZone community and get the full member experience.
Join For FreeThe fluent builder pattern is one of the most useful patterns, especially when you want to build complex objects. For example, say you want to build a complex object by initiating the builder, calling the respective setters, and finally, calling the build method. Once the build method is executed, you will get the desired model/entity/pojo object back.
Email email = Email.EmailBuilder()
.setFrom("Test@gmail.com")
.setTo("mail@gmail.com")
.setSubject("Test with only required Fields")
.setContent(" Required Field Test").build();
This looks quite simple but there is one catch. If the object building is complex and there are too many setters methods, then normally the developer's tendency is to forget some of the setters and build the object. Doing so, many of the important object attributes will be null, and so, no setters are being called for the same.
In many enterprise applications, there will be a core entity like Order/Loan, and it might get initiated in many sections of the code, missing the set attribute can be a costly process in terms of development and maintenance. So, what do you do?
The answer is to force the developer to set all required setter methods before calling the build method. Doing so, all required attributes will get initialized and build object is in your desired state. But how to force the developer? The answer is through the fluent builder pattern.
What Is the Fluent Builder Pattern?
Fluent builder pattern is a style of coding which force the developer to create the object in sequence by calling each setter method one after the another until all required attributes are set.
Let’s go in detail about how to achieve the fluent builder pattern. The fluent builder pattern is similar to any fluent API call, but this is used to build the object. For achieving fluent builder, we are going to create an interface chain where each interface method will return the next interface type. Confused? Let me explain with an example. For the sake of simplicity, we will try to build the Email Object, which will contain all the info to send the email.
public final class Email {
// To Address. Multiple Address separated by ","
String to;
//From Address
String from;
// Subject of the email
String subject;
// Content of the email
String content;
// BCC optional
String bcc;
// CC Optional
String cc;
}
Let’s define the mandatory and optional attributes. Mandatory attributes are from,to,subject and content. Optional attributes are cc and bcc. Here we need to create interface chain for the setting the attributes as follow:
// Interface to Set From
interface EmailFrom {
EmailTo setFrom(String from);
}
//Interface to Set To
interface EmailTo {
EmailSubject setTo(String to);
}
//Interface to Set subject
interface EmailSubject {
EmailContent setSubject(String subject);
}
// Interface to set Content
interface EmailContent {
EmailCreator setContent(String content);
}
// Final Email Creator Class
interface EmailCreator {
EmailCreator setBCC(String bcc);
EmailCreator setCC(String cc);
Email build();
}
If you see for each attribute that there is one interface and one method, the return type of the method is the next interface in the sequence. Creating the builder class is easy, it needs to implement all our interfaces defined as part of the interface chain as follows:
public static class EmailBuilder implements EmailFrom, EmailTo,
EmailSubject, EmailContent, EmailCreator{
String to;
String from;
String subject;
String content;
String bcc;
String cc;
/**
* Private emailbuilder to prevent direct object creation
*/
private EmailBuilder(){
}
/**
* Getting the instance method
* @return
*/
public static EmailFrom getInstance(){
return new EmailBuilder();
}
...
}
We need to provide the instance method for the builder and make the constructor private so that the developer is forced to create the builder object as we want. Another important point is that the instance method should return the first interface type in the chain. For any optional attribute that is required, we need to create methods in the last interface in the chain along with the build method.
Let's create the Email Object with only mandatory and non-mandatory attributes as follows:
//Creating basic email object without cc and bcc
Email email = Email.EmailBuilder.getInstance().setFrom("Test@gmail.com").setTo("mail@gmail.com")
.setSubject("Test with only required Fields").setContent(" Required Field Test").build();
System.out.println(email);
//Creating the full Email Object with cc and bcc
email = Email.EmailBuilder.getInstance().setFrom("Test@gmail.com").setTo("mail@gmail.com")
.setSubject("Test with ALL Fields").setContent(" ALL Field Test").setBCC("bcc@gmail.com")
.setCC("cc@gmail.com").build();
System.out.println(email);
Conclusion
If your requirement is to build a complex object for which you want to set the mandatory attributes and avoid making any mistakes, then the fluent builder will be more useful rather than the traditional builder pattern.
You can find the entire code here.
Published at DZone with permission of Milind Deobhankar. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments