The builder pattern is useful to avoid a huge list of constructors for a class. Let's imagine a class that store the mode of transport (of an employee for instance). Here is the constructor that takes a MetroLine object as parameter:
Now we need a constructor for the one that uses the car, the bus or the train:
For some of them, we need to indicate a travel allowance:
We have employees that have several modes of transport to go to work. We realize that the list of constructors is coming to a mess. Each new parameter leads to an exponent duplication of constructors. If some parameters have the same type, it becomes very confusing. A solution to this issue would be to first build a fake object and then fill it calling methods on it:
The list of methods is no more exponent but the state of the object may be inconsistent. A better solution would be to set all the parameters to an object of another class, a pre-constructor, and then pass this object to the constructor of ModeOfTransport:
This solution is even better. We only have a valid ModeOfTransport object. However, the ModeOfTransport constructor can be called with a half-filled pre-constructor. So the pre-constructor should be a builder and should have a method that returns the ModeOfTransport object. This method will only return an object if the builder has been correctly filled, otherwise it returns null:
So the solution is to use a builder class. Let's see the structure of the code on the UML class diagram:
- Builder: Abstract interface for creating objects (product).
- Concrete Builder: Provides implementation for Builder. It is an object able to construct other objects. Constructs and assembles parts to build the objects.
The builder pattern can be used for objects that contain flat data (html code, SQL query, X.509 certificate...), that is to say data that can't be easily edited. This type of data can not be edited step by step and must be edited at once. The best way to construct such an object is to use a builder class.
In Java, the
StringBuilder classes follow the builder design pattern. They are used to build
You can easily decide to use it. At worst, the pattern is useless.
Starting from a plain old class with a public constructor, implementing the design pattern is not very expensive. You can create the builder class aside your code. Then you will have to remove the existing constructor calls to use the builder instead. The refactoring is hardly automatic.
This design pattern has only small drawbacks. It may lead to small redundancies between the class and the builder structures but the both class have usually different structures. However, it is expensive to evolve to an abstract factory.
The refactoring is hardly automatic. It should be done manually.
- Put the builder term in the name of the builder class to indicate the use of the pattern to the other developers.
- Build your builder class as a fluent interface. It would increase the pattern interest.
- If the target class contains flat data, your builder class can be constructed as a Composite that implements the Interpreter pattern.