8

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:

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?

Andy
  • 1,325

3 Answers3

8

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.

Caleth
  • 12,190
3

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.

Joop Eggen
  • 2,629
2

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.

Doc Brown
  • 218,378