Java Builder Pattern – Why Use Inner Class Over Separate File

design-patternsjavaobject-oriented

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?

Best Answer

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.