wake-up-neo.com

Anonym gegen benannte innere Klassen? - Best Practices?

Ich habe eine Klasse, nennen wir sie LineGraph, die ein Liniendiagramm rendert. Ich muss eine Unterklasse erstellen, aber die abgeleitete Klasse wird nur an einer Stelle verwendet und ist an die Klasse gekoppelt, die sie verwendet. Also benutze ich eine innere Klasse.

Ich sehe zwei Möglichkeiten, dies zu tun:

Anonyme innere Klasse

public class Gui {
    LineGraph graph = new LineGraph() {
        // extra functionality here.
    };
}

Benannte innere Klasse

public class Gui {
    MyLineGraph graph = new MyLineGraph();

    private class MyLineGraph extends LineGraph {
        // extra functionality here.
    }
}

Ich bin kein Fan anonymer innerer Klassen, denn ehrlich gesagt finde ich es einfach wirklich hässlich. Aber bei einer Unterklasse, die nur an einer Stelle verwendet wird, ist ein benannter Inner Class Overkill? Was ist die akzeptierte Praxis?

43
Joe Attardi

Ein Vorteil anonymer innerer Klassen ist, dass niemand sie irgendwo anders verwenden kann, wohingegen eine benannte innere Klasse verwendet werden kann (wenn auch nur von der Klasse, die sie erstellt hat, wenn sie privat gemacht wird). Es ist eine kleine Unterscheidung, aber es bedeutet, dass Sie eine innere Klasse davor schützen können, versehentlich anderweitig verwendet zu werden.

Wenn Sie die anonyme innere Klasse verwenden, kann jeder, der Ihren Code liest, ein wenig Kopf haben - "diese Klasse wird nur hier und nirgendwo sonst verwendet." Wenn Sie eine benannte innere Klasse sehen, könnte jemand denken, sie würde an mehreren Stellen in der Klasse verwendet.

Sie sind sich sehr ähnlich, daher ist kein Punkt ein Spielveränderer. Ich denke, es hilft nur zur Klarheit, wenn Sie anonyme innere Klassen für Einzelanwendungen und benannte innere Klassen verwenden, wenn diese innerhalb der Klasse mehrfach verwendet werden.

49
Daniel Lew

(Kontrapunkt zu Daniel Lew)

Ein Nachteil anonymer innerer Klassen besteht darin, dass niemand sie irgendwo anders verwenden kann, wohingegen eine benannte innere Klasse verwendet werden kann (wenn auch nur von der Klasse, die sie erstellt hat, wenn sie privat gemacht wird). Es ist eine kleine Unterscheidung, aber es bedeutet, dass Sie dazu beitragen können, dass eine innere Klasse nicht versehentlich anderswo neu erstellt wird.

Die Verwendung der anonymen inneren Klasse macht es für jeden schwieriger, Ihren Code zu lesen, da er dann diese Klasse analysieren muss, die aus dem Nichts gekommen ist. Mit einer benannten inneren Klasse können Sie die Quelle mehr organisieren.

Ich habe Fälle gesehen, in denen es zwei (oder mehr) anonyme innere Klassen mit genau demselben Code gibt. Insbesondere in GUIs (wo Sie möglicherweise mehrere Steuerelemente ausführen, die dieselbe Aktion ausführen) kann dies auftauchen (und ich spreche von Produktionscode, nicht von meinen Studenten geschriebenem Code).

Das Problem der Lesbarkeit geht in beide Richtungen, manche Leute finden anonyme innere Klassen besser, da sie sehen, was an einem Ort vor sich geht, andere es als Ablenkung empfinden. Dieser Teil hängt von persönlichen Vorlieben ab.

Eine Klasse statisch zu machen, ist effizienter. Wenn Sie eine anonyme innere Klasse in einer Instanz deklarieren, wird mehr Overhead anfallen. Wenn Sie keinen Zugriff auf die Instanzvariablen benötigen, ist dies verschwenderisch (aber wahrscheinlich nicht zu befürchten.) bis es sich als Problem darstellt).

Meine persönliche Präferenz ist die Verwendung von nicht anonymen Klassen, da sie bei späteren Änderungen des Codes mehr Flexibilität bieten.

36
TofuBeer

Warum müssen Sie es subclassieren? Wenn es nur darum geht, eine vorhandene virtuelle Methode zu überschreiben, denke ich, dass eine anonyme innere Klasse in Ordnung ist. Wenn Sie zusätzliche Funktionen hinzufügen, würde ich eine benannte Klasse verwenden. Ich würde es jedoch zu einer verschachtelten Klasse machen (d. H. Mit dem Modifizierer static) - ich finde es einfacher, sie zu begründen :)

10
Jon Skeet

Machen Sie das einfachste, was möglicherweise funktioniert : Verwenden Sie die anonyme innere Klasse.

Wenn Sie später feststellen, dass Sie einen breiteren Anwendungsbereich benötigen, überarbeiten Sie den Code, um dies zu unterstützen.

(Sie würden dasselbe mit Variablen tun, indem Sie sie in den genauesten Bereich setzen. Es ist sinnvoll, dasselbe mit anderen Quellen-Assets zu tun.)

8
Jeff Grigg

Anonyme innere Klassen sind in Eclipse (das ist was ich benutze) schwer zu debuggen. Sie können Variablenwerte/Injektionswerte nicht durch Klicken mit der rechten Maustaste anzeigen.

4
Kapsh

Meine Faustregel: Wenn die anonyme innere Klasse klein sein soll, bleiben Sie bei einer anonymen Klasse. Klein ist definiert als ungefähr 20 - 30 Zeilen oder weniger. Wenn es länger wird, wird es meiner Meinung nach unlesbar, daher mache ich es zu einer benannten inneren Klasse. Ich erinnere mich Einmal eine 4000+ Linie anonyme innere Klasse sehen.

3
Avrom

Ein Nachteil innerer Klassen ist, dass sie nicht statisch sein können. Dies bedeutet, dass ein Verweis auf die äußere Klasse enthalten wird, die sie enthält. 

Nicht statische innere Klassen können ein Problem sein. Zum Beispiel wurde kürzlich eine innere Klasse serialisiert, die äußere Klasse war jedoch nicht serialisierbar. Die versteckte Referenz bedeutete, dass auch die äußere Klasse serialisiert wurde, was natürlich fehlgeschlagen ist, aber es dauerte eine Weile, um herauszufinden, warum.

Wo ich arbeite, werden statische innere Klassen (soweit möglich) in unseren Kodierungs-Best Practices empfohlen, da sie weniger verstecktes Gepäck tragen und schlanker sind.

3
user15299

Anonyme Klassen können keinen Konstruktor haben, da sie keinen Namen haben. Wenn Sie andere Variablen als diejenigen in den Konstruktoren der zu erweiternden Klasse übergeben müssen, sollten Sie eine (statische) benannte innere Klasse verwenden. Dies kann manchmal durch die Verwendung abschließender Variablen in der umgebenden Methode/Code überwunden werden, aber es ist imho ein bisschen hässlich (und kann dazu führen, was Robin sagte).

2
druidu

Anonyme innere Klassen wären in der Regel der Weg. Ich finde sie sehr gut lesbar. Wenn jedoch die Instanz dieser Klasse jemals serialisiert werden muss (auch wenn es sich nur um ein anderes Feld handelt), würde ich dringend die Verwendung von benannten inneren Klassen empfehlen. Die Namen der anonymen inneren Klassen im Bytecode können sich sehr leicht ändern und die Serialisierung kann dadurch beeinträchtigt werden.

2
Adam Crume

Anonyme Klassen:

  • kann nichts static in der Definition haben (statische Klasse, statisches Feld, statischer Initialisierer usw.)
  • felder können in Eclipse nicht geprüft werden
  • kann nicht als Typ verwendet werden (Foo$1 myFoo=new Foo$1(){int x=0;} funktioniert nicht)
  • kann nicht anhand des Klassennamens in Eclipse gefunden werden (die Suche nach Foo$1 funktioniert für mich nicht)
  • kann nicht wiederverwendet werden

Anonyme Klassen können jedoch einen Initialisierer wie {super.foo(finalVariable+this.bar);} haben.

Benannte innere Klassen haben diese Einschränkungen nicht, aber selbst wenn eine Klasse nur in einer langen Prozedur verwendet wird, muss die Deklaration auf die nächste benannte Klasse verschoben werden.

Ich persönlich bevorzuge anonyme innere Klassen, wenn die Einschränkungen nicht zutreffen, weil:

  • Ich weiß, dass zusätzliche Felder nur in der Klassendefinition referenziert werden.
  • Eclipse kann sie problemlos in verschachtelte Klassen konvertieren.
  • Ich muss keine Variablen kopieren, die ich verwenden möchte. Ich kann sie nur als endgültig erklären und auf sie verweisen. Dies ist besonders nützlich, wenn ich viele Parameter habe.
  • Der Code, der interagiert, ist nahe beieinander.
1
yingted

Ich habe kein Problem mit einfachen anonymen Klassen. Wenn es jedoch aus mehr als wenigen Codezeilen oder mehreren Methoden besteht, ist eine innere Klasse klarer. Ich denke auch, dass sie unter bestimmten Bedingungen niemals verwendet werden sollten. Zum Beispiel, wenn sie Daten zurückgeben müssen.

Ich habe Code gesehen, bei dem ein abschließendes Array von 1 Element verwendet wird, um Daten von einem Aufruf an eine anonyme innere Klasse zurückzugeben. Innerhalb der Methode der anon-Klasse wird das einzelne Element festgelegt und dieses 'Ergebnis' extrahiert, sobald die Methode abgeschlossen ist. Gültiger, aber hässlicher Code.

1
Robin

Ich hatte gerade diese Diskussion heute mit meinem Kollegen und suchte nach allgemeiner Meinung.

Ich stimme mit TofuBeer überein. Wenn Ihr Code mehr als zwei Zeilen umfasst, handelt es sich wahrscheinlich nicht um eine einmalige Anwendung, die möglicherweise eines Tages wiederverwendet wird. Wenn Sie ein Formular mit einem MVC-Muster erstellen, haben Sie möglicherweise 20 kontrollierbare Elemente auf einer Seite, anstatt die Ansicht mit Unmengen an Anonymous-Klassen zu überspielen (zum Teufel wurde Ihre Ansicht wahrscheinlich mit einem GUI-Builder erstellt und der Code wurde automatisch erstellt.) Wenn Sie die Quelle nicht einmal eine Option bearbeiten, werden Sie wahrscheinlich jedes Element einem Controller zuführen. Sie können innere Klassen innerhalb des Controllers verschachteln, um mit jeder anderen Handler/Listener-Schnittstelle zu arbeiten, die Ihre Ansicht erfordert. Dadurch wird der Code sehr gut organisiert, insbesondere wenn Sie eine Konvention haben, dass Ihre Handler-Klasse mit dem Namen des GUI-Elements benannt werden muss (z. B. backButtonHandler für ein backButtonElement). Das hat für uns sehr gut funktioniert, und wir haben ein Tool für die automatische Registrierung geschrieben (wenn Sie einen Controller in einer Ansicht registrieren, sucht die Ansicht mithilfe des Elementnamens nach inneren Klassen und verwendet sie für einen Handler für jedes benannte Element). Dies ist bei anonymen Klassen nicht möglich und macht den Controller viel recycelbarer. 

TLDR: im Zweifelsfall eine benannte innere Klasse schreiben. Sie wissen nie, ob jemand Ihren Code eines Tages wiederverwenden möchte (es sei denn, es handelt sich um zwei Zeilen, dann müssen Sie sich fragen, ob dieser Code riecht?). Code, der gut organisiert ist, hat auf lange Sicht viel höhere Vorteile, insbesondere wenn sich Ihr Projekt in der Wartung befindet.

0
dolbysurnd

Ich denke, das, was Sie getan haben, ist in diesem Fall absolut sinnvoll und egal, wie Sie es betrachten. Ich denke, Sie spalten wirklich Haare mit diesem speziellen Problem. Sie sind sich beide so ähnlich und beide funktionieren.

0
Mike Pone

Bei anonymen inneren Klassen können wir den Status der eingeschlossenen Klassenmitglieder nicht ändern. Sie müssen als endgültig deklariert werden.

0

Ich denke, das ist Geschmackssache. Ich bevorzuge anonyme Kurse für Functors . Aber in Ihrem Fall würde ich eine innere Klasse verwenden, da Sie meiner Meinung nach mehr als nur ein paar Codezeilen einpacken, vielleicht mehr als nur eine Methode. Und es würde die Tatsache betonen, dass es der Superklasse Funktionalität hinzufügt, indem sie in die Klasse eingefügt wird, anstatt irgendwo in einer Methode versteckt zu werden. Und wer weiß, vielleicht brauchen Sie vielleicht irgendwann die Unterklasse woanders. Dies hängt natürlich davon ab, wie viel Sie über die Entwicklung Ihrer Software wissen. Ansonsten einfach eine Münze werfen. :)

0
Andrei Vajna II