21

Many Builder Pattern examples make the Builder an inner class of the object it builds.

This makes some sense since it indicates what the Builder builds. However, in a statically typed language we know what the Builder builds.

On the other hand if the Builder is an inner class, you should know what class the Builder builds without looking inside of the Builder.

Also, having the builder as an inner class reduces the number of imports since it can be referenced by the outer class--if you care about that.

And then there are practical examples where the Builder is in the same package, but not an inner class, like StringBuilder. You know that the Builder should build a String because it is named so.

That being said, the only good reason I can think of for making a Builder an inner class is that you know what the class' Builder is without knowing its name or relying on naming conventions. For example, if StringBuilder was an inner class of String I probably would have known it existed sooner than I did (speculative).

Are there any other reasons to make the Builder an inner class or does it just come down to preference and ritual?

27

I think that the reason for doing this is so that the inner class (the Builder) can access private members of the class that it is building.

From http://docs.oracle.com/javase/tutorial/java/javaOO/nested.html

Non-static nested classes (inner classes) have access to other members of the enclosing class, even if they are declared private.

...

Consider two top-level classes, A and B, where B needs access to members of A that would otherwise be declared private. By hiding class B within class A, A's members can be declared private and B can access them.

...

As with instance methods and variables, an inner class is associated with an instance of its enclosing class and has direct access to that object's methods and fields.

Here's some code to try to illustrate this:

class Example {

    private int x;

    public int getX() { return this.x; }

    public static class Builder {

        public Example Create() {
            Example instance = new Example();
            instance.x = 5; // Builder can access Example's private member variable
            return instance;
        }
    }
}

As a static class, Builder doesn't have a specific instance of Example that it is tied to. However, given an instance of Example (or one that it creates itself) Builder can still access the private members of that instance.

  • Great answer, that makes sense! However builder patterns usually have a static inner class and would only be able to access static private members of the outer class. If you had a builder for an instantiated class that would be all kinds of weird. – Nathanial Jan 23 '14 at 17:03
  • 1
    @Nathanial not at all, private instance variables are also accessible: ideone.com/7DyjDR – amon Jan 23 '14 at 17:11
  • 1
    @nathanial: Yes, but the builder is not manipulating the class; it is manipulating an object of the class that the builder itself has instantiated. – Robert Harvey Jan 23 '14 at 17:31
  • @amon I see what you did there. Thanks for the explanation! – Nathanial Jan 23 '14 at 17:39
  • Specifically, it gives the builder access to a private constructor for the class being built, allowing that class to be immutable (all fields final) and only instantiable via the builder. – Matthew McPeak Jun 7 at 19:55
1

There is no "should" in this case. Defining a builder inside another class or having it separate is orthogonal to the Builder pattern. Many examples do this due to convenience of presenting the code in one consistent file (also for accessing private members but that depends on context as well). Feel free to do otherwise

  • Not sure why this answer was down voted, for any other reason than, "because that's not how we do it in Java." The Builder Pattern provides a wrapper around a constructor that takes a bunch of parameters. If the constructor takes those parameters, then there is no need for the Builder object to access private members. – Greg Burghardt Jul 13 '16 at 16:45

protected by gnat Jul 13 '16 at 13:28

Thank you for your interest in this question. Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).

Would you like to answer one of these unanswered questions instead?

Not the answer you're looking for? Browse other questions tagged or ask your own question.