user4081847
user4081847

Reputation: 23

What is the difference, if any, between these builder patterns?

Is there a difference between declaring an instance of your parent class in your builder and initializing each Field using that variable and declaring each variable separately again inside the builder then declaring the builder as part of your constructor to initialize each Field?

public class Foo {

    public int i;
    public String s;

    private Foo(Builder builder) {
        i = builder.i;
        s = builder.s;
    }

    public static class Builder {

        private int i;
        private String s;

        public Builder i(int i) {
            this.i = i;
            return this;
        }

        public Builder s(String s) {
            this.s = s;
            return this;
        }

        public Foo build() {
            return new Foo(this);
        }
    }

}

public class Foo {

    public int i;
    public String s;

    public static class Builder {

        private final Foo mFoo = new Foo();

        public Builder i(int i) {
            mFoo.i = i;
            return this;
        }

        public Builder s(String s) {
            mFoo.s = s;
            return this;
        }

        public Foo build() {
            return mFoo;
        }
    }

}

Upvotes: 2

Views: 60

Answers (1)

BeeOnRope
BeeOnRope

Reputation: 64925

The first approach is the canonical one.

As I see it, the main limitations of the second approach are:

  • You cannot make members of Foo (the object you are constructing) final since they are assigned after construction.
  • You must either declare the builder in the class that it is building, so that it has access to private members or setters, or else declare non-private members or setter methods so that the Builder can access them, even though that level of access might not be appropriate post-building.
  • The object Foo under construction goes through several different states which may be invalid. Depending on what methods you use to construct the object in this incremental way, you may be limited in the validations you can do. The usual builder pattern collects all the state for the object to be built and then builds it, allowing the constructor to do all necessary validation on the final state.
  • The builder cannot build more than one object. In the usual builder pattern, you can call build() multiple times to build multiple objects, possibly interleaved with calls to builder methods to modify subsequent objects.

The only real upside I can see to the second approach is that you save some boilerplate - you don't have to re-declare the members in the builder object, and potentially better performance since the values don't have to be copied out of the Builder to the final object.

Upvotes: 5

Related Questions