Telescoping Constructor Pattern
Both static factories and constructors are not well-suited to handle a large number of parameters. For example, if a class has 6 fields, and you want to create constructors for 2 parameters, 3 parameters, ..., you can use the telescoping constructor pattern as shown below.
However, even with this, if there are too many parameters, it can be confusing to read the code to understand the meaning of each value, and you may mistakenly enter values for parameters with the same type.
JavaBeans Pattern
The JavaBeans pattern creates an object with a parameterless constructor and then calls setter methods to set the values of the desired parameters.
The JavaBeans pattern allows you to create instances without confusion even when there are many parameters. However, creating an object requires multiple calls to setter methods, and consistency is broken until the object is fully completed. For this reason, the class cannot be made immutable.
Builder Pattern
The Builder pattern is mainly used because it combines the robustness of the telescoping constructor pattern and the readability of the JavaBeans pattern.
Instead of creating the object directly, the client obtains a builder object by calling the constructor with only the required parameters. Then, the client sets the desired optional parameters using a kind of setter method provided by the builder object. Finally, the client calls the parameterless `build()` method to obtain the desired object.
The constructor within the `Builder` class receives only the required parameters, and the remaining optional parameters are filled in using a kind of setter method. Finally, a completed `NutritionFactsWithBuilderPattern` object is created through the `build()` method. The `NutritionFactsWithBuilderPattern` class is immutable, and the builder's setter methods return the builder itself, so they can be chained. This approach is called a fluent API or method chaining.
From the client's perspective, the builder pattern makes it easy to write and read the code.
Builder Pattern Works Well with Hierarchically Designed Classes
The `Pizza.Builder` class is a generic type that uses recursive type bounds, and it adds the abstract method `self()` to support method chaining without type conversion in subclasses. In subclasses, you just need to return the class itself from this abstract method.
Now, let's look at the New York Pizza and Calzone Pizza, which are subclasses of Pizza, and experience the flexibility of the builder pattern.
The `build()` method defined in each subclass builder returns a concrete subclass. The ability of a subclass method to return a type that is a subtype of the type returned by the superclass method is called covariant return typing. With this feature, clients don't need to perform type casting.
From the client's perspective, you can use the `Pizza` enum and each subclass's enum, and you can complete the object with the appropriate method for each.
Disadvantages of the Builder Pattern
- You need to create a builder object.
- The code can be verbose.
Summary
If a constructor or static factory method needs to handle many parameters, consider using the builder pattern.
References
- Effective Java
Comments0