The builder pattern is just a way to build an object similar to what a constructor does, so why use a builder pattern instead of plain old constructors?
A Factory Design Pattern is used when the entire object can be easily created and object is not very complex. Whereas Builder Pattern is used when the construction process of a complete object is very complex.
Advantages of the Builder pattern include: Allows you to vary a product's internal representation. Encapsulates code for construction and representation. Provides control over steps of construction process.
Builder focuses on constructing a complex object step by step. Abstract Factory emphasizes a family of product objects (either simple or complex). Builder returns the product as a final step, but as far as the Abstract Factory is concerned, the product gets returned immediately. Builder often builds a Composite.
The builder pattern simplifies the creation of objects. It also simplifies the code as your do not have to call a complex constructor or call several setter methods on the created object. The builder pattern can be used to create an immutable class.
I agree with your view that a Builder
is really just a glorified constructor, and that the "builder pattern is just a way to build an object similar to what a constructor does".
However, here are a few of scenarios where the complexity of constructing an object makes the use of a Builder
compelling.
In Java, StringBuilder
is commonly used when building a string over a period of time, or rather, within a complex procedure. For instance, if a server is communicating with a client over a socket, and wants to append some client responses to the string, but not others, and perhaps remove certain responses that were previously appended,the StringBuilder
class can be used to do so. At the end of the client/server session, the server can invoke StringBuilder#toString
to get the built String
.
If a constructor has dozens of parameters, it may make the code more readable or easy to maintain to use a builder.
E.g.
new Foo(1,2,3,4,5,6,7,8,9,10,11,12)
Vs.
Foo.newBuilder()
.bar(1)
.bar(2)
.quux(3)
...
.build()
Similar to the "lots of parameters" scenario, I think that the scenario where a builder is most compelling is when constructing a complex object graph. The other answers in this question refer to the telescoping anti-pattern. This scenario (building a complex object graph) can lead to "telescoping", which the Builder
helps resolve.
For instance, imagine you have an object-oriented pipeline interface, where a Pipeline
depends on Sequence
which depends on Stage
. A PipelineBuilder
would not only provide a nice wrapper around the constructor of Pipeline
, but also around the constructors Sequence
and Stage
, allowing you to compose a complex Pipeline
from a single Builder
interface.
Instead of telescoping constructors like so:
new Pipeline(
new Sequence(
new Stage(
new StageFunction() {
public function execute() {...}
}
),
new Stage(
new StageFunction() {
public function execute() {...}
}
)
)
)
A PipelineBuilder
would allow you to "collapse" the telescope.
Pipeline.newBuilder()
.sequence()
.stage(new StageFunction () {
public function execute() {...}
})
.stage(new StageFunction () {
public function execute() {...}
})
.build()
(Even though I have used indentation in a way that is reflective of the telescoping constructors, this is merely cosmetic, as opposed to structural.)
From the Wikipedia page:
The telescoping constructor anti-pattern occurs when the increase of object constructor parameter combination leads to an exponential list of constructors. Instead of using numerous constructors, the builder pattern uses another object, a builder, that receives each initialization parameter step by step and then returns the resulting constructed object at once
So if I have an object requiring many construction parameters, and those parameters are required in a variety of combinations (thus making some parameters optional) then a builder is a good approach.
e.g. I could create multiple different constructors for an object, or I could do the following:
new ObjectBuilder().withParam1(1).withParam4(4).withParam19(19).build();
thus allowing me to select the parameters required, and not have to define many different constructors. Note also that the above can allow you to populate a builder, and set parameters/call build()
multiple times to create a set of related objects easily.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With