Warum sollte ein Builder eine innere Klasse sein, anstatt in einer eigenen Klassendatei?

24

Viele Builder PatternBeispiele machen das zu Buildereiner inneren Klasse des Objekts, das es erstellt.

Dies macht Sinn, da es anzeigt, was die BuilderBuilds sind. In einer statisch typisierten Sprache wissen wir jedoch, was die BuilderBuilds sind.

Auf der anderen Seite, wenn Builderes sich um eine innere Klasse handelt, sollten Sie wissen, welche Klasse die Klasse erstellt, Builderohne in die Klasse zu schauen Builder.

Wenn Sie den Builder als innere Klasse haben, wird auch die Anzahl der Importe verringert, da auf ihn von der äußeren Klasse verwiesen werden kann.

Und dann gibt es praktische Beispiele, bei denen das Builderim selben Paket ist, aber keine innere Klasse, wie StringBuilder. Sie wissen, dass das ein bauen Builder sollte , Stringweil es so heißt.

Abgesehen davon ist der einzige gute Grund, warum ich mir vorstellen kann, Buildereine innere Klasse zu bilden, dass Sie wissen, was die Klasse Builderist, ohne ihren Namen zu kennen oder sich auf Namenskonventionen zu verlassen. Wenn zum Beispiel StringBuildereine innere Klasse von Stringmir gewesen wäre, hätte ich wahrscheinlich gewusst, dass sie früher existiert als ich (spekulativ).

Gibt es noch andere Gründe, aus denen man Buildereine innere Klasse macht, oder kommt es nur auf Vorlieben und Rituale an?

Nathanial
quelle

Antworten:

30

Ich denke, der Grund dafür ist, dass die innere Klasse (der Builder) auf private Mitglieder der Klasse zugreifen kann, die sie erstellt.

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

Nicht statische verschachtelte Klassen (innere Klassen) haben Zugriff auf andere Mitglieder der einschließenden Klasse, auch wenn sie als privat deklariert sind.

...

Betrachten Sie zwei Klassen der obersten Ebene, A und B, in denen B Zugriff auf Mitglieder von A benötigt, die ansonsten als privat deklariert würden. Durch das Ausblenden von Klasse B in Klasse A können die Mitglieder von A als privat deklariert werden und B kann auf sie zugreifen.

...

Wie bei Instanzmethoden und -variablen ist eine innere Klasse einer Instanz ihrer einschließenden Klasse zugeordnet und hat direkten Zugriff auf die Methoden und Felder dieses Objekts.

Hier ist ein Code, um dies zu veranschaulichen:

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

Als statische Klasse verfügt Builder nicht über eine bestimmte Instanz von Example, an die es gebunden ist. Bei einer Instanz von Example (oder einer Instanz, die selbst erstellt wird) kann Builder jedoch weiterhin auf die privaten Mitglieder dieser Instanz zugreifen.

Dr. Wily's Lehrling
quelle
Tolle Antwort, das macht Sinn! Builder-Muster haben jedoch normalerweise eine statische innere Klasse und können nur auf statische private Mitglieder der äußeren Klasse zugreifen. Wenn Sie einen Builder für eine instanziierte Klasse hätten, wäre das alles andere als seltsam.
Nathanial
1
@ Nathanial überhaupt nicht, private Instanzvariablen sind ebenfalls zugänglich: ideone.com/7DyjDR
amon
1
@nathanial: Ja, aber der Builder manipuliert die Klasse nicht. Es manipuliert ein Objekt der Klasse, das der Builder selbst instanziiert hat.
Robert Harvey
@amon ich sehe was du da gemacht hast. Danke für die Erklärung!
Nathanial
Insbesondere erhält der Builder Zugriff auf einen privaten Konstruktor für die zu erstellende Klasse, sodass diese Klasse unveränderlich (alle Felder final) und nur über den Builder instanziierbar ist.
Matthew McPeak
1

In diesem Fall gibt es kein "sollte". Das Definieren eines Builders in einer anderen Klasse oder das Separieren eines Builders ist orthogonal zum Builder-Muster. Viele Beispiele tun dies, um den Code in einer konsistenten Datei darzustellen (auch für den Zugriff auf private Mitglieder, dies hängt jedoch auch vom Kontext ab). Fühlen Sie sich frei, etwas anderes zu tun

AZ01
quelle
Ich bin mir nicht sicher, warum diese Antwort aus einem anderen Grund als "weil wir es in Java nicht so machen" abgelehnt wurde. Das Builder-Muster stellt einen Wrapper um einen Konstruktor bereit, der eine Reihe von Parametern akzeptiert. Wenn der Konstruktor diese Parameter verwendet, muss das Builder-Objekt nicht auf private Member zugreifen.
Greg Burghardt