Почему конструктор должен быть внутренним классом, а не в своем собственном файле классов?

24

Многие Builder Patternпримеры делают Builderвнутренний класс объекта, который он создает.

Это имеет некоторый смысл, поскольку указывает на то, что Builderстроит. Однако в статически типизированном языке мы знаем, что Builderстроит.

С другой стороны, если Builderэто внутренний класс, вы должны знать, какой класс Builderстроит, не заглядывая внутрь Builder.

Кроме того, наличие конструктора в качестве внутреннего класса уменьшает количество импортов, так как на него может ссылаться внешний класс - если вы заботитесь об этом.

И затем есть практические примеры, когда Builderобъект находится в одном пакете, но не во внутреннем классе, например StringBuilder. Вы знаете, что Builder должен построить, Stringпотому что он назван так.

При этом единственная причина, по которой я могу придумать создание Builderвнутреннего класса, состоит в том, что вы знаете, что такое класс « Builder, не зная его имени и не полагаясь на соглашения об именах. Например, если бы это StringBuilderбыл внутренний класс, Stringя, вероятно, знал бы, что он существует раньше, чем я (умозрительный).

Есть ли другие причины делать Builderвнутренний класс или он просто сводится к предпочтениям и ритуалам?

Nathanial
источник

Ответы:

30

Я думаю, что причина этого заключается в том, что внутренний класс (Builder) может получить доступ к закрытым членам класса, который он создает.

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

Нестатические вложенные классы (внутренние классы) имеют доступ к другим членам включающего класса, даже если они объявлены закрытыми.

...

Рассмотрим два класса верхнего уровня, A и B, где B необходим доступ к членам A, которые в противном случае были бы объявлены закрытыми. Скрывая класс B в классе A, члены A могут быть объявлены частными, и B может получить к ним доступ.

...

Как и в случае с методами и переменными экземпляра, внутренний класс связан с экземпляром включающего его класса и имеет прямой доступ к методам и полям этого объекта.

Вот некоторый код, чтобы попытаться проиллюстрировать это:

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;
        }
    }
}

Как статический класс, Builder не имеет определенного экземпляра Example, к которому он привязан. Однако, учитывая экземпляр Example (или тот, который он создает сам), Builder все еще может получить доступ к закрытым членам этого экземпляра.

Ученик доктора Вилли
источник
Отличный ответ, это имеет смысл! Однако шаблоны компоновщика обычно имеют статический внутренний класс и могут получить доступ только к статическим закрытым членам внешнего класса. Если бы у вас был конструктор для экземпляра класса, это было бы очень странно.
Натаниал
1
@Nathanial совсем нет, закрытые переменные экземпляра также доступны: ideone.com/7DyjDR
amon
1
@nathanial: Да, но строитель не манипулирует классом; это манипулирование объектом класса, созданным самим создателем.
Роберт Харви
@ amon Я вижу, что ты там сделал. Спасибо за объяснение!
Натаниал
В частности, он предоставляет разработчику доступ к частному конструктору для создаваемого класса, позволяя этому классу быть неизменным (все поля final) и создаваться только через конструктор.
Мэтью Макпик
1

В этом случае нет «должен». Определение построителя внутри другого класса или его отделение ортогонально шаблону Строителя. Многие примеры делают это из-за удобства представления кода в одном согласованном файле (также для доступа к закрытым членам, но это также зависит от контекста). Не стесняйтесь делать иначе

AZ01
источник
Не уверен, почему за этот ответ проголосовали по любой другой причине, кроме «потому что это не то, как мы делаем это в Java». Шаблон Builder предоставляет обертку вокруг конструктора, которая принимает несколько параметров. Если конструктор принимает эти параметры, тогда объекту Builder не требуется доступ к закрытым членам.
Грег Бургхардт