Builder Design Pattern
Builder design pattern is a creational design pattern like Factory Pattern and Abstract Factory Pattern.
For
What are the traditional ways of creating an object of a class?
We can provide either constructor or a static factory method to get the
For Example,
For the sake of brevity, we will assume that portal is providing
We will create
- Telescoping Constructor Pattern or Telescoping Static Factories
- JavaBeans Pattern
Telescoping Constructor Pattern
In this pattern, you
What sort of constructor or static factories should you write for this class? Traditionally, programmers
public class MovieTicketBooking { private final String movie; // Name of the Movie private final int totalTickets; // Total tickets booked private final int popcorn; // quantity of popcorn private final int pizza; // quantity of Pizza private final int burger; // quantity of burger private final int coke; // quantity of coke public MovieTicketBooking(String movie, int totalTickets) { this(movie, totalTickets, 0); } public MovieTicketBooking(String movie, int totalTickets, int popcorn) { this(movie, totalTickets, popcorn, 0); } public MovieTicketBooking(String movie, int totalTickets, int popcorn, int pizza) { this(movie, totalTickets, popcorn, pizza, 0); } public MovieTicketBooking(String movie, int totalTickets, int popcorn, int pizza, int burger) { this(movie, totalTickets, popcorn, pizza, burger, 0); } public MovieTicketBooking(String movie, int totalTickets, int popcorn, int pizza, int burger, int coke) { this.movie = movie; this.totalTickets = totalTickets; this.popcorn = popcorn; this.pizza = pizza; this.burger = burger; this.coke = coke; } }
When you want to create an instance, you use the constructor with the shortest parameter list containing all the parameters you want to set.
MovieTicketBooking movieTest = new MovieTicketBooking("3 Idiots", 5, 2, 0, 3, 5);
Disadvantages
- Typically this constructor invocation will require many parameters that you don’t want to set, but you’re forced to pass a value for them anyway. In this case, even if I don't want to order Pizza, I need to include it with value 0 as I want burger and coke to be included in my order.
-
With “only” six parameters this may not seem so bad, but it quickly gets out of hand as the number of parameters increases. Also adding one new filed to the class will require
to write entire new constructor. - Writing and reading a code with telescoping constructor pattern needs lots of attention. The reader is left wondering what all those values mean and must carefully count parameters to find out. Long sequences of identically typed parameters can cause subtle bugs. If the client accidentally reverses two such parameters, the compiler won’t complain, but the program will misbehave at runtime.
JavaBeans pattern
A second alternative when you are faced with many constructor parameters is the JavaBeans pattern, in which you call a parameterless constructor to create the object and then call setter methods to set each required parameter and each optional parameter of interest:
public class MovieTicketBooking { private String movie; // Name of the Movie private int totalTickets; // Total tickets booked private int popcorn; // quantity of popcorn private int pizza; // quantity of Pizza private int burger; // quantity of burger private int coke; // quantity of coke public MovieTicketBooking() { } public void setMovie(String movie) { this.movie = movie; } public void setTotalTickets(int totalTickets) { this.totalTickets = totalTickets; } public void setPopcorn(int popcorn) { this.popcorn = popcorn; } public void setPizza(int pizza) { this.pizza = pizza; } public void setBurger(int burger) { this.burger = burger; } public void setCoke(int coke) { this.coke = coke; } }
It is easy to create instances, and easy to read the resulting code:
MovieTicketBooking movieTest = new MovieTicketBooking (); movieTest.setMovie("3 Idiots"); movieTest.setTotalTickets(5); movieTest.setPopcorn(2); movieTest.setBurger(3); movieTest.setCoke(5);
Here you do not need to set
Disadvantages
This pattern has none of the disadvantages of the telescoping constructor pattern. Unfortunately, the JavaBeans pattern has serious disadvantages of its own.
-
Because construction is split across multiple calls, this approach has the disadvantage of objects leaving in an inconsistent
state and you have to put in extra effort to ensure thread safety. - JavaBeans pattern also precludes the possibility of making a class immutable.
Builder Design Pattern
To overcome all the disadvantages of above two patterns, Builder Design Pattern was introduced.
According to GOF:
The Builder Pattern separates the construction of a complex object from its representation so that the same construction process can create different representations.
The builder design pattern provides a way to build complex immutable objects. Steps to implement Builder Design Pattern:
For better understanding, please check below code snippet while reading this steps:
- Make all fields private final
-
Create inner class Builder which is having
of private fields as in outer class. (Inner class fields are not required to have the same name as outer class, but it is good practice to keep them same as outer class)same number - In Builder class, create one constructor for all the required fields and create setter methods for optional fields.
-
All
this setter methods should return Builder class object to achieve method chaining. (Check client code for method chaining) - Create copy constructor in outer class which uses Builder object fields.
public class MovieTicketBooking { private final String movie; // Name of the Movie private final int totalTickets; // Total tickets booked private final int popcorn; // quantity of popcorn private final int pizza; // quantity of Pizza private final int burger; // quantity of burger private final int coke; // quantity of coke private MovieTicketBooking(Builder builder) { movie = builder.movie; totalTickets = builder.totalTickets; popcorn = builder.popcorn; pizza = builder.pizza; burger = builder.burger; coke = builder.coke; } public static class Builder{ private final String movie; private final int totalTickets; private int popcorn; private int pizza; private int burger; private int coke; public Builder(String movie, int totalTickets) { this.movie = movie; this.totalTickets = totalTickets; } public Builder popcorn(int val){ popcorn = val; return this; } public Builder pizza(int val){ pizza = val; return this; } public Builder burger(int val){ burger = val; return this; } public Builder coke(int val){ coke = val; return this; } public MovieTicketBooking build() { return new MovieTicketBooking(this); } } }
The process to write client code:
- The client calls a constructor with all the required fields and gets a Builder object. Here builder is a static member class of the class it builds.
- The client calls setter like methods to set each optional parameter of interest. The Builder's setter methods return the Builder itself so that invocations can be chained.
-
Finally the client calls the build method to generate the new object which is immutable.
For Example,
MovieTicketBooking movieTest = MovieTicketBooking.Builder("3 Idiots", 5) .popcorn(2) .burger(3) .coke(5) .build();
Advantages
-
A minor advantage of builders over constructors is that builders can have multiple
varargs parameters. Constructors, like methods, can have only onevarargs parameter. Because builders use separate methods to set each parameter, they can have as manyvarargs parameters as you like, up to one per setter method. - The Builder pattern is flexible. A single builder can be used to build multiple objects. The parameters of the builder can be tweaked between object creations to vary the objects. for example,
MovieTicketBooking.Builder movieBuilder = MovieTicketBooking.Builder("3 Idiots", 5); MovieTicketBooking movieTest1 = movieBuilder.popcorn(2).build(); MovieTicketBooking movieTest2 = movieBuilder.coke(5).build();
- Builder design pattern is used to build immutable objects without much complex logic in object building process. To know more about creating immutable objects, read our post How To Create Immutable Class In Java
Disadvantage
- In order to create an object, you must first create its builder. While the cost of creating the builder is unlikely to be noticeable in practice, it could be a problem in some performance critical situations.
- Also, the Builder pattern is more verbose than the telescoping constructor pattern, so it should be used only if there are enough parameters, say, four or more.
In summary, the Builder pattern is a good choice when designing classes whose constructors or static factories would have more than a handful of parameters, especially if most of those parameters are optional.
Existing implementations in JDK
All implementations of java.lang.Appendable are in fact good example of use of Builder pattern in java. e.g.
- java.lang.StringBuilder#append() [Unsynchronized class]
- java.lang.StringBuffer#append() [Synchronized class]
- java.nio.ByteBuffer#put() (also on CharBuffer, ShortBuffer, IntBuffer, LongBuffer, FloatBuffer and DoubleBuffer)
That's all for this topic. If you guys have any suggestions or queries, feel free to drop a comment. We would be happy to add that in our post. You can also contribute your articles by creating contributor account here.
Happy Learning 🙂
If you like the content on CodePumpkin and if you wish to do something for the community and the planet Earth, you can donate to our campaign for planting more trees at CodePumpkin Cauvery Calling Campaign.
We may not get time to plant a tree, but we can definitely donate ₹42 per Tree.
About the Author
Tags: Core Java, Creational Design Patterns, Design Patterns, Java
Comments and Queries
If you want someone to read your code, please put the code inside <pre><code> and </code></pre> tags. For example:<pre><code class="java"> String foo = "bar"; </code></pre>For more information on supported HTML tags in disqus comment, click here.