Dlaczego budowniczy powinien być klasą wewnętrzną zamiast własnego pliku klasy?

24

Wiele Builder Patternprzykładów tworzy Builderwewnętrzną klasę obiektu, który buduje.

Ma to jakiś sens, ponieważ wskazuje, co Builderbuduje. Jednak w języku typowanym statycznie wiemy, co się Builderkompiluje.

Z drugiej strony, jeśli Builderjest to klasa wewnętrzna, powinieneś wiedzieć, jaką klasę Builderbuduje, nie zaglądając do wnętrza Builder.

Ponadto posiadanie konstruktora jako klasy wewnętrznej zmniejsza liczbę importów, ponieważ klasa zewnętrzna może do niego odwoływać - jeśli o to dbasz.

A potem są praktyczne przykłady, w których Builderjest w tym samym pakiecie, ale nie w wewnętrznej klasie StringBuilder. Wiesz, że Builder powinien zbudować a, Stringponieważ tak się nazywa.

To powiedziawszy, jedyny dobry powód, dla którego mogę wymyślić Builder stworzyć wewnętrzną klasę, jest to, że wiesz, czym jest klasa, Buildernie znając jej nazwy ani nie polegając na konwencjach nazewnictwa. Na przykład, jeśli byłaby to StringBuilderklasa wewnętrzna String, prawdopodobnie wiedziałbym, że istniał wcześniej niż ja (spekulacyjne).

Czy istnieją inne powody, aby uczynić Builderklasę wewnętrzną, czy sprowadza się to do preferencji i rytuału?

Nathanial
źródło

Odpowiedzi:

30

Myślę, że powodem tego jest, aby klasa wewnętrzna (Konstruktor) mogła uzyskać dostęp do prywatnych członków klasy, którą buduje.

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

Niestatyczne klasy zagnieżdżone (klasy wewnętrzne) mają dostęp do innych członków klasy zamykającej, nawet jeśli są zadeklarowane jako prywatne.

...

Rozważ dwie klasy najwyższego poziomu, A i B, w których B potrzebuje dostępu do członków A, które w innym przypadku zostałyby uznane za prywatne. Ukrywając klasę B w klasie A, członkowie A mogą zostać uznani za prywatnych, a B może uzyskać do nich dostęp.

...

Podobnie jak w przypadku metod i zmiennych instancji, klasa wewnętrzna jest powiązana z instancją klasy zamykającej i ma bezpośredni dostęp do metod i pól tego obiektu.

Oto kod, aby spróbować to zilustrować:

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

Jako klasa statyczna Builder nie ma określonej instancji klasy Przykład, z którą jest powiązany. Jednak biorąc pod uwagę instancję Przykład (lub taką, którą sam tworzy) Konstruktor może nadal uzyskiwać dostęp do prywatnych członków tej instancji.

Dr Wily's Apprentice
źródło
Świetna odpowiedź, to ma sens! Jednak wzorce konstruktorów zwykle mają statyczną klasę wewnętrzną i mogą uzyskiwać dostęp do statycznych prywatnych członków klasy zewnętrznej. Gdybyś miał konstruktora instancji klasy, byłoby to dziwne.
Nathanial
1
@Nathanial wcale nie, zmienne instancji prywatnych są również dostępne: ideone.com/7DyjDR
amon
1
@nathanial: Tak, ale budowniczy nie manipuluje klasą; manipuluje obiektem klasy, który sam konstruktor utworzył.
Robert Harvey
@amon Widzę co tam zrobiłeś. Dziękuję za wyjaśnienie!
Nathanial
W szczególności daje konstruktorowi dostęp do prywatnego konstruktora dla budowanej klasy, pozwalając tej klasie być niezmienną (wszystkie pola końcowe) i tworzyć ją tylko za pośrednictwem konstruktora.
Matthew McPeak
1

W tym przypadku nie ma „powinien”. Definiowanie konstruktora w innej klasie lub oddzielanie go jest prostopadłe do wzorca konstruktora. Wiele przykładów robi to ze względu na wygodę prezentacji kodu w jednym spójnym pliku (również w celu uzyskania dostępu do członków prywatnych, ale zależy to również od kontekstu). Możesz zrobić inaczej

AZ01
źródło
Nie jestem pewien, dlaczego głosowanie zostało odrzucone z jakiegokolwiek innego powodu niż: „ponieważ nie w ten sposób robimy to w Javie”. Wzorzec konstruktora zapewnia opakowanie wokół konstruktora, który pobiera kilka parametrów. Jeśli konstruktor pobierze te parametry, obiekt Builder nie musi uzyskiwać dostępu do prywatnych członków.
Greg Burghardt,