Often I see the implementation of the builder pattern (in Java) to be like this:
public class Foo {
private Foo(FooBuilder builder) {
// get alle the parameters from the builder and apply them to this instance
}
public static class FooBuilder {
// ...
public Foo build() {
return new Foo(this); // <- this part is what irritates me
}
}
}
Examples also here:
- https://stackoverflow.com/questions/25130510/builder-pattern-in-java
- https://www.javacodegeeks.com/2013/01/the-builder-pattern-in-practice.html
Why do people introduce the strong (mutual) dependency between builder and type to build?
EDIT: I mean, I know that by its nature the builder is tied to the class I want to build an instance from (FooBuilder -> Foo
). What I questioning is: why is there the necessity for the other way around (Foo -> FooBuilder
)
On the contrary I see (less often) implementations that create a new instace of Foo
when the builder is created and set the fields on the instance of Foo
when the appropriate builder-methods are called. I like this approach better, because it still has a fluent API and does not tie the class to its builder. Is there any downside of this other approach?
3 Answers 3
It boils down to never having a Foo in a half constructed state
Some reasons that spring to mind:
The builder's is by nature tied to the class it is constructing. You can think of the intermediate states of the builder as partial application of the constructor, so your argument that it is too coupled isn't persuasive.
By passing the whole builder in, fields in MyClass can be final, making reasoning about MyClass easier. If the fields are not final, you could just as easily have fluent setters than a builder.
-
1. by its nature the builder is tied to the class I want to build an instance from (FooBuilder -> Foo). What I questioning is: why is there the necessity for the other way around (Foo -> FooBuilder) 2. I see the point with the final modifier, but besides that modifier, the FooBuilder can simply set the fields of Foo (even if they are private, because FooBuilder is part of Foo), and if i don't create setters, the instance is still immutable, isn't it?Andy– Andy09/28/2016 09:32:51Commented Sep 28, 2016 at 9:32
-
It boils down to never having a Foo in a half constructed state, even if it is only ever internal to the builder. Would you think it a problem that in a class with a large overload set of constructors, there was a "strong (mutual) dependency" between the constructors and the rest of the class? Because that's what a Builder is - a concise way of expressing lots of similar constructorsCaleth– Caleth09/28/2016 09:40:27Commented Sep 28, 2016 at 9:40
-
Thanks for the answer (about never having an inconsistent state), that makes it clear. I don't like the answer but I understand it now. When you incorporate that in you answer, I will accept it.Andy– Andy09/28/2016 10:42:56Commented Sep 28, 2016 at 10:42
The builder will hold mutable fields, set with methods. The actual class (Foo
) can then create immutable final
fields from the builder.
So the Builder is a stateful class.
But the builder could alse have called new Foo(x, y, z)
. That would be more one-directional, better style IMHO. As then the anti-pattern, a FooBuilder field or such would not be possible. On the other hand the FooBuilder guarantees some integrity of the data.
On the other hand FooBuilder plays two roles: for building with a fluent API, and for presenting data to the constructor. It is an event-type class for the constructor. In a overdesigned code the constructor params could be kept in some FooConstructorParams.
Because a "Builder" is typically used to solve the "telescoping constructor problem", especially in context of immutable classes. See this link for a full-fledged example.
Consider what the alternatives would look like:
public static class FooBuilder {
// works with immutable classes, but leads to telescoping constructor
public Foo build() {
return new Foo(par1, par2, par3, ....);
}
}
Or:
public static class FooBuilder {
// does not work for immutable classes:
public Foo build() {
var foo = new Foo();
foo.Attribute1=par1;
foo.Attribute2=par2;
//...
return foo;
}
}
So especially for immutable classes, if you want no constructor with a bunch of parameters, there is actually no alternative.
-
I know what problem the builder pattern solves. But you didn't answer my question why the implementation often looks like the example given. Even Josh Bloch in the article you linked does not. However, Caleth does in his/her comment.Andy– Andy09/28/2016 10:40:59Commented Sep 28, 2016 at 10:40
-
@Andy: I gave an example to clarify why this answers your question.Doc Brown– Doc Brown09/28/2016 11:27:11Commented Sep 28, 2016 at 11:27
-
Actually, your second example is not necessarily mutable. If you do not implement setter-methods it's immutable. But I now see, where you are heading at.Andy– Andy09/28/2016 11:32:35Commented Sep 28, 2016 at 11:32
-
@Andy: I could actually rewrite the example using setters if you prefer Java idioms instead of C# idioms. But if
foo.Attribute1=par1
is possible,Foo
is definitely mutable, even in Java. Immutable classes need to forbid any mutation of their state after construction, neither by setters, nor by methods mutating their state, nor by exposing public member attributes.Doc Brown– Doc Brown09/28/2016 11:35:55Commented Sep 28, 2016 at 11:35 -
"So especially for immutable classes".... But a class without setters will still appear immutable from the outside. Whether they are final or not is a nice-to-have.Esben Skov Pedersen– Esben Skov Pedersen09/28/2016 11:37:26Commented Sep 28, 2016 at 11:37
Foo
constructor is public ?