loading...

Effective Java Tuesday! The Builder Pattern!

kylec32 profile image Kyle Carter ・4 min read

Effective Java Review (36 Part Series)

1) Effective Java Tuesday! Let's Consider Static Factory Methods 2) Effective Java Tuesday! The Builder Pattern! 3 ... 34 3) Effective Java Tuesday! Singletons! 4) Effective Java Tuesday! Utility Classes! 5) Effective Java Tuesday! Prefer Dependency Injection! 6) Effective Java Tuesday! Avoid Creating Unnecessary Objects! 7) Effective Java Tuesday! Don't Leak Object References! 8) Effective Java Tuesday! Avoid Finalizers and Cleaners! 9) Effective Java Tuesday! Prefer try-with-resources 10) Effective Java Tuesday! Obey the `equals` contract 11) Effective Java Tuesday! Obey the `hashCode` contract 12) Effective Java Tuesday! Override `toString` 13) Effective Java Tuesday! Override `clone` judiciously 14) Effective Java Tuesday! Consider Implementing `Comparable` 15) Effective Java Tuesday! Minimize the Accessibility of Classes and Member 16) Effective Java Tuesday! In Public Classes, Use Accessors, Not Public Fields 17) Effective Java Tuesday! Minimize Mutability 18) Effective Java Tuesday! Favor Composition Over Inheritance 19) Effective Java Tuesday! Design and Document Classes for Inheritance or Else Prohibit It. 20) Effective Java Tuesday! Prefer Interfaces to Abstract Classes 21) Effective Java! Design Interfaces for Posterity 22) Effective Java! Use Interfaces Only to Define Types 23) Effective Java! Prefer Class Hierarchies to Tagged Classes 24) Effective Java! Favor Static Members Classes over Non-Static 25) Effective Java! Limit Source Files to a Single Top-Level Class 26) Effective Java! Don't Use Raw Types 27) Effective Java! Elminate Unchecked Warnings 28) Effective Java! Prefer Lists to Array 29) Effective Java! Favor Generic Types 30) Effective Java! Favor Generic Methods 31) Effective Java! Use Bounded Wildcards to Increase API Flexibility 32) Effective Java! Combine Generics and Varargs Judiciously 33) Effective Java! Consider Typesafe Hetergenous Containers 34) Effective Java! Use Enums Instead of int Constants 35) Effective Java! Use Instance Fields Instead of Ordinals 36) Effective Java! Use EnumSet Instead of Bit Fields

It's time for episode two of the effective Java review series. The topic of today is the builder pattern. Just like our previous chapter this is another creational pattern.

When we are faced with a class that has a significant number of optional members what is the best way to create these objects? The three methods detailed in Effective Java are telescoping constructors, the JavaBean pattern, and the builder pattern. Let's walk through these methods and see where the first two fall short and how the builder pattern can shine.

Option 1: Telescoping Constructors
First up is my least favorite option if you have more than one or two optional parameters. The telescoping constructor. A telescoping constructor is basically a group of constructors that basically covers all the available permutations of parameters that could be used to create an object. Let's look at an example:

public Burger(String bunType)
public Burger(String bunType, List<String> condiments)
public Burger(String bunType, List<String> condiments, String meat)
public Burger(String bunType, List<String> condiments, String meat, String temperature)

Looking at these constructors you can see where it gets it's name. Telescoping constructors suffer from a problem talked about in my previous post in this series. With multiple parameters of the same type it can be easy to get lost in what each parameter is what. (Although hat tip to my favorite IDE Intellij for giving little tool tips giving the parameter name). With the above example the problem could be wondering if the fourth or the fifth parameter was the meat. Better not mess that up or else you may end up with a rare meat cooked beef 😕. Another awkwardness that can be seen above is what if I only want want one condiment? Well I need to create collection anyway with something like Collection.singletonList("Ketchup") (Hey look, a factory method!). One idea would be to use a varargs but you can only use one varargs argument in a function and it must be at the end so that makes its use limited in this case. A benefit of this method is that you can make an immutable objects which is a good thing indeed. If you only have a single optional parameter or two it can work but as we can see it has some issues.

Option 2: JavaBeans
The JavaBeans method is quite straightforward. You start off with having a no arguments constructor and then create setters for each member variable. Something along the lines of:

Burger burger = new Burger();
burger.setBread("Sour dough");
burger.setMeat("Beef");

This is pretty straightforward but has it's problems. One of the big ones to me is your object can be an inconsistent state as you are building it. There is a lot less control which is not great. It also feels a little messy and verbose. Another shortcoming of this approach is the lack of ability to create immutable objects. Effective Java goes over a method where some people "freeze" their object but that seems fairly error prone and messy. If there is no risk of half created object and immutability is not desired this method can work fine but we should also consider what this chapter is about.

Option 3: Builder Pattern
This brings us to what this chapter is about, the builder pattern. This pattern gives us the best of both worlds. We get the safety of the telescoping constructor but also get vastly improved readability like the JavaBeans method (I would argue better than the JavaBeans even). In this pattern we create a static class internal to the object we want to create traditionally simply called Builder. The methods of the builder object allow the user to set the values of the object and then it returns the builder object back. This allows for a clean fluent API. Once all the calls are made the user calls a parameterless build method at which point the object is actually created. The build method allows a moment to make sure the object is in a solid state. Personally when I have required attributes with a builder pattern I put them in the initial build call.

What does this give us? For one, the option of immutability. While not always taken advantage of it is an attribute that I personally think is beneficial to have. However the greatest benefit is through the fluent API we have a much more maintainable codebase. It also makes optional parameters much easier to handle. If a consumer of the class doesn't need to set an attribute they simply don't call the method. We can also see that we could call methods to construct multiple attributes with lists and don't run into any of the issues with varargs that we may with the above methods.

Other languages have ways of handling this with named parameters and optional parameters. This is one of the reasons I like Kotlin. But without this option a builder pattern is solid. There has to be an easier way and indeed there is. One tools that I think should be in every Java developers is Lombok. This processor takes a ton of the boiler plate of writing Java out which is great. They also have a @Builder annotation that will make this very clean for us. There are some people that think Lombok is a bad idea but I am definitely not one of them.

So there you have it. The builder pattern. Have you had any success with this pattern? Are there any pitfalls that you have experienced? Let us know in the comments below.

Effective Java Review (36 Part Series)

1) Effective Java Tuesday! Let's Consider Static Factory Methods 2) Effective Java Tuesday! The Builder Pattern! 3 ... 34 3) Effective Java Tuesday! Singletons! 4) Effective Java Tuesday! Utility Classes! 5) Effective Java Tuesday! Prefer Dependency Injection! 6) Effective Java Tuesday! Avoid Creating Unnecessary Objects! 7) Effective Java Tuesday! Don't Leak Object References! 8) Effective Java Tuesday! Avoid Finalizers and Cleaners! 9) Effective Java Tuesday! Prefer try-with-resources 10) Effective Java Tuesday! Obey the `equals` contract 11) Effective Java Tuesday! Obey the `hashCode` contract 12) Effective Java Tuesday! Override `toString` 13) Effective Java Tuesday! Override `clone` judiciously 14) Effective Java Tuesday! Consider Implementing `Comparable` 15) Effective Java Tuesday! Minimize the Accessibility of Classes and Member 16) Effective Java Tuesday! In Public Classes, Use Accessors, Not Public Fields 17) Effective Java Tuesday! Minimize Mutability 18) Effective Java Tuesday! Favor Composition Over Inheritance 19) Effective Java Tuesday! Design and Document Classes for Inheritance or Else Prohibit It. 20) Effective Java Tuesday! Prefer Interfaces to Abstract Classes 21) Effective Java! Design Interfaces for Posterity 22) Effective Java! Use Interfaces Only to Define Types 23) Effective Java! Prefer Class Hierarchies to Tagged Classes 24) Effective Java! Favor Static Members Classes over Non-Static 25) Effective Java! Limit Source Files to a Single Top-Level Class 26) Effective Java! Don't Use Raw Types 27) Effective Java! Elminate Unchecked Warnings 28) Effective Java! Prefer Lists to Array 29) Effective Java! Favor Generic Types 30) Effective Java! Favor Generic Methods 31) Effective Java! Use Bounded Wildcards to Increase API Flexibility 32) Effective Java! Combine Generics and Varargs Judiciously 33) Effective Java! Consider Typesafe Hetergenous Containers 34) Effective Java! Use Enums Instead of int Constants 35) Effective Java! Use Instance Fields Instead of Ordinals 36) Effective Java! Use EnumSet Instead of Bit Fields

Posted on by:

kylec32 profile

Kyle Carter

@kylec32

Backend Architect at MasterControl

Discussion

markdown guide
 

I didn't know this but it's gonna be really useful. I use to see this pattern a lot when using api's but until now I had never understood how it worked