There are three ways to create new objects in Java programming language:
I prefer the builder pattern over the other two methods.
Joshua Bloch described the builder pattern and the benefits of using it in Effective Java. He did an excellent job and I will not repeat these benefits in this blog post.
Instead, I will describe three other reasons why I prefer the builder pattern over the telescoping constructor pattern and the Javabeans pattern.
1. It Helps You to Enforce Better Design
Using either the telescoping constructor pattern or the Javabeans pattern means that the properties of the created object must be created before the actual object is created.
This might or might not be a problem.
If the properties of the created object are fetched by using an external service, it is not a problem. However, if the properties are created in the method which creates the "target" object, it is a problem.
In the latter scenario, the lifecycle of the created objects is often bound to the lifecycle of the "target" object.
A DDD aggregate is a cluster of domain objects that can be treated as a single unit. An example may be an order and its line-items, these will be separate objects, but it's useful to treat the order (together with its line items) as a single aggregate.
The builder pattern can help you to design your code in a such way that your domain model is divided into aggregates. This means that the all objects belonging to the aggregate are created by the aggregate root object (Order) and can be accessed only via the aggregate root object.
This moves the construction relation to the logic to the place where it belongs.
2. It Makes You Think
Writing code in the traditional way is easy because you don't have to think. All you have to do is write the code which copies information from one place to another. It might take some time to do it, but it isn't a problem to you because you are on your comfort zone.
Maybe you want to just crunch code without thinking what you are doing.
I am not like that (and you shouldn’t be either).
The builder pattern forces you to think about your objects. To be more specific, it forces you to think about the following things:
- You have to figure out the mandatory and optional properties of an object.
- You have to identify the properties which lifecycle is bound to the lifecycle of the created object and design the builder so that it emphasizes this.
- You have to decide what properties cannot be updated after the object is created (and mark these properties as final).
- You have to decide what properties can be updated and find the best way to update them.
Finding answers to these questions help you to write better code. I can guarantee that if you take the time to find the answers to these questions, your code will look a lot better than the code written on autopilot.
3. It Helps You to Create Domain-specific Languages
If you use create new objects by using the telescoping constructor pattern or the Javabeans pattern, it is hard to add business meaning to your code. You can try to improve the situation by following these principles:
- The only way you can add business meaning to constructor arguments is to name the arguments in a proper way. This is difficult to do and even if you get it right, the results aren't optimal.
- If you use setters, you can of course name the setter methods in a way which adds business meaning to them. However, how often have you seen setter methods which are named following this principle?
99 times out of a 100 the created objects are just objects without meaning. They hold data. That is all.
When you use the builder pattern, you can create a domain-specific language (DSL) for creating new objects by naming the methods of your builder class. This helps you to add business meaning to the code which creates new objects.
This raises one question: how can I update the properties of my objects?
You can of course be boring and use setter methods for updating the individual properties of your objects. But you can do something totally different as well.
Instead of updating individual properties, you can group these properties into meaningful groups and update the values of these properties in a single method. If you name this method correctly, you can create a DSL for updating the information of existing objects.
It Is Not a Silver Bullet
Blake Caldwell says that the builder pattern is basically a less error prone alternative for constructors. I agree with him.
The first thing which you notice when you start to use the builder pattern is that the code which creates new objects is easier to write and read. However, after some time you might notice other benefits as well. I know that I did.
However, it is important that you understand that the builder pattern is not a silver bullet.
I think that no one should follow a best practice just because it is a best practice. This applies to the builder pattern as well.
If your object has only a few constructor arguments, it makes no sense to use the builder pattern. However, because of the benefits described in this blog post (and in Effective Java), you should consider using the builder pattern every time when you have to create new objects.