Чому будівельник повинен бути внутрішнім класом замість власного файлу класів?


24

Багато Builder Patternприкладів робить цеBuilder робиться внутрішній клас об'єкта, який він будує.

Це має певний сенс, оскільки вказує на те, що Builderбудується. Однак зі статистично набраною мовою ми знаємо, що такеBuilder будується.

З іншого боку, якщо Builderце внутрішній клас, ви повинні знати, який клас Builderбудує, не заглядаючи всередину Builder.

Крім того, наявність будівельника як внутрішнього класу зменшує кількість імпорту, оскільки на нього може посилатися зовнішній клас - якщо вам це важливо.

А потім є практичні приклади, коли Builderв одному пакеті, але не внутрішній клас, як StringBuilder. Ви знаєте, що Builder слід будувати, Stringтому що він названий так.

Однак, я можу подумати про створення Builderвнутрішнього класу - це те, що ви знаєте, що таке клас, Builderне знаючи його назви і не покладаючись на умовні позначення. Наприклад, якщо StringBuilderце був внутрішній клас оString я, мабуть, знав би, що він існував раніше, ніж я (спекулятивний).

Чи є якісь інші причини зробити Builderвнутрішній клас чи це просто зводиться до уподобань та ритуалів?

Відповіді:


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 (або той, який він створює сам), Builder все ще може отримати доступ до приватних членів цього екземпляра.


Чудова відповідь, це має сенс! Однак моделі будівельників зазвичай мають статичний внутрішній клас і матимуть доступ лише до статичних приватних членів зовнішнього класу. Якби у вас був конструктор для розробленого класу, який був би дивним.
Натаніал

1
@Nathanial зовсім не доступні, приватні змінні екземпляри також доступні: ideone.com/7DyjDR
amon

1
@nathanial: Так, але будівельник не маніпулює класом; це маніпулювання об'єктом класу, який сам будівельник створив.
Роберт Харві

@amon Я бачу, що ти там робив. Дякую за пояснення!
Натаніал

Зокрема, він надає будівельникові доступ до приватного конструктора для класу, який будується, що дозволяє цьому класу бути непорушним (усі поля остаточні) та миттєвим лише через будівельника.
Меттью Макпік

1

У цьому випадку "не повинно". Визначення будівельника всередині іншого класу або окремий його ортогональний для моделі Builder. Багато прикладів роблять це завдяки зручності представлення коду в одному послідовному файлі (також для доступу до приватних членів, але це також залежить від контексту). Не соромтеся робити інакше


Не впевнений, чому за цю відповідь було проголосовано з будь-якої іншої причини, ніж "тому, що це не так, як ми це робимо на Java". Шаблон Builder забезпечує обгортку навколо конструктора, який приймає купу параметрів. Якщо конструктор приймає ці параметри, то об’єкт Builder не потребує доступу до приватних членів.
Грег Бургхардт
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.