Vor kurzem hatte ich Gelegenheit, Javas & lt; Instanz & gt; .new zu verwenden Konstruieren, um eine Instanz einer inneren Klasse zu erstellen.
Obwohl ich der Meinung bin, dass es eine vernünftige Begründung dafür gibt, scheint seine eher obskure Syntax es für Wartungsprogrammierer etwas schwieriger zu machen.
Aber ich frage mich, ob die Notwendigkeit für & lt; instance & gt; .new ein Indikator dafür ist, dass es besser wäre, ein bisschen Refactoring zu machen, um die innere Klasse zu einer Klasse der obersten Ebene in ihrem Elternpaket zu machen, geben Sie ihr einen Konstruktor Ein Verweis auf seinen übergeordneten Typ wäre ideal und fügt den Feldern, auf die er vom übergeordneten Typ zugreift, Zugriffsmethoden oder Zugriffsmodifizierer auf Paketebene hinzu.
Gibt es Anwendungsfälle für & lt; instance & gt; .new, die nicht durch Umgestaltung der inneren Klasse in eine äußere Klasse behandelt werden konnten?
Ich hätte nicht gesagt, dass es Code-Geruch ist.
Wenn die Kopplung zwischen der äußeren und der inneren Klasse stark ist und Ihre Verwendung der inneren Klasse für eine gute Verkapselung steht, dann würde ich sagen, dass Sie dieses Konstrukt verwenden. Auf der anderen Seite, wenn die Abstraktion bereits undicht ist, ist es wahrscheinlich eine bessere Idee, die innere Klasse zu einer Klasse auf oberster Ebene zu machen.
Die Verwendung von outer.new Inner()
kann oder kann nicht der Beweis für eine undichte Abstraktion sein.
(Das Konstrukt wurde aus gutem Grund in die Sprache aufgenommen, und die Tatsache, dass es nur selten benötigt wird, macht seine Verwendung nicht ungültig.)
Gibt es Anwendungsfälle für .new, die nicht durch Umgestaltung der inneren Klasse in eine äußere Klasse behandelt werden könnten?
Es gibt im Allgemeinen keine wichtigen Anwendungsfälle für diese Syntax, da Sie den inneren Konstruktor immer verbergen können und die äußere Klasse innere Klasseninstanzen durch Factory-Methoden zurückgeben kann (wenn Sie den inneren Typ trotzdem nach außen offen legen wollen):
%Vor%Kundencode:
%Vor%Also ist der "Code-Geruch" (wenn es wirklich ein Code-Geruch ist) nicht in der Tatsache, dass eine innere Klasse vorhanden ist, sondern in der Tatsache, dass sein Konstruktor öffentlich verfügbar ist (und verwendet wird). Aber nach einer sorgfältigen Auswertung könnten Sie feststellen, dass dies in Ordnung ist
UPDATE : Ein gutes Zeichen dafür, dass die Kapselung unterbrochen ist, ist, wenn Outer
Instanzen wahrscheinlich eine kürzere Lebensdauer haben als Inner
Instanzen. In diesem Fall können Inner
-Instanzen einen Verweis auf Outer
für einen längeren Zeitraum behalten, als der Autor des Outer
beabsichtigt hat. Dies kann sogar zu Speicherlecks führen.
Wenn Sie innere Klassen verwenden, wird Ihr Code schwieriger zu verstehen, da die Klassen ihren inneren Zustand teilen und daher mit dem Prinzip der Informationsverbergung brechen. Manchmal kann die Verwendung einer inneren Klasse eine Lösung leicht zu schreiben machen, aber ich denke, dass es die meiste Zeit nicht die beste / sauberste Lösung ist.
Ich benutze innere Klasse vor allem, wenn eine Methode einer Klasse Multithread sein muss.
Tatsächlich gibt es zwei saubere Möglichkeiten, Threads zu deklarieren:
Erstellen Sie eine Runnable
-Klasse (die Methode enthält Multithread) und lassen Sie den Client selbst einen neuen Thread erstellen. Der Nachteil ist, dass der Client sich bewusst sein muss, dass er mit Multithreading umgehen muss.
Geben Sie die Jobklasse nicht als Runnable
an, sondern definieren Sie lieber eine inner-class
, die selbst Runnable
implementiert. Natürlich muss diese inner-class
nicht public
sein und wird daher von einer der öffentlichen dedizierten Methode in der äußeren Klasse (dh der Job-Klasse) instanziiert.
Daher behandelt der Client diese public
-Methode, ohne zu wissen, dass ein Thread im Hintergrund erstellt wird. Wenn Entwickler sich morgen dafür entscheiden, das Multithreading innerhalb dieser Jobklasse aus irgendeinem Grund zu entfernen, kann der Client vollständig unverändert bleiben.
Und damit diese innere Klasse Felder der äußeren Klasse erbt, deklariere ich sie nicht als statisch. (auch verschachtelte Klasse im Gegensatz zur inneren Klasse genannt)
Tags und Links java class inner-classes instantiation code-smell