7 Stimmen

Sollte ich JFrame/JPanel Unterklasse oder nicht?

Ich war es gewohnt, die Fensterklassen in anderen Programmierumgebungen zu unterklassifizieren, aber in den Java-Tutorials sehe ich normalerweise etwas wie

JPanel p = new JPanel();
p.setLayout(new BoxLayout(p, BoxLayout.PAGE_AXIS));

p.add(aComponent);
p.add(anotherComponent);

Welche Konventionen gibt es in Java bezüglich der Unterklassifizierung von Top-Container-Klassen?

6voto

Qwerky Punkte 17904

Verwenden Sie das gleiche Prinzip wie für alle Java-Klassen. Wenn Sie das Verhalten oder die Funktionalität ändern oder erweitern, dann erweitern Sie auf jeden Fall JPanel o JFrame . Die Kunst besteht darin, sorgfältig zu überlegen und zu entscheiden, ob Sie wirklich etwas hinzufügen. Unter Die meisten Fälle, in denen ich sehe, wie Menschen ihre JFrame es ist unnötig und falsch;

public class MyFrame extends JFrame {
  public static void main(String[] args) {
    new MyFrame().setVisible(true);
  }
}

Warum sollte man verlängern? JFrame ? Sie haben nichts hinzugefügt! Die Komposition ist eine viel bessere Option.

Erweitern Sie JPanel ist ein wenig anders. JPanel ist eine ziemlich abstrakte Idee, seine nur ein generischer Container für andere Komponenten. IMHO ist es gültig, Unterklasse JPanel um ein konkreteres Panel zu erstellen, das Sie dann in Ihrer Anwendung verwenden. Es fördert OOP und Kapselung.

Angenommen, Ihr GUI hat zwei Hauptanzeigebereiche: einen mit einigen Schaltflächen/Steuerungen/Eingaben und einen anderen, der die Ausgabe (z. B. in einem Textbereich) anzeigt. Es ist durchaus akzeptabel, die Unterklasse JPanel um ein ControlPanel zu erstellen, das die Schaltflächen/Steuerelemente/Eingaben enthält. Dadurch wird der gesamte Code in ein nettes, übersichtliches Modul verschoben, das die Klasse aufräumt, die das Hauptmodul enthält und behandelt JFrame .

3voto

rurouni Punkte 2251

Hierfür gibt es keine Regel, es kommt darauf an, wie Sie über Ihr Objekt denken. Sie können ein JPanel haben, das ein bestimmtes Layout und Verhalten hat, also z.B. ein VideoViewerPanel. Aber auch dieses VideoViewerPanel kann ein JPanel enthalten, das nur dazu da ist, einige Buttons anzuordnen, so dass Sie es nicht explizit benennen und einfach als JPanel verwenden.

2voto

G-Man Punkte 1321

Ich denke, das hängt mit dem Liskovschen Substitutionsprinzip zusammen, Sie sollten sich damit befassen.

Liskov-Substitutionsprinzip

Liskov-Substitutionsprinzip: Angewandtes Beispiel

2voto

jfpoilpret Punkte 10291

Eine bekannte und gute Praxis ist es, die Unterklassifizierung von Top-Level-Containern ( JFrame , JDialog , JInternalFrame ).

Betreffend JPanel sind mehrere Verfahren im Einsatz:

  • Unterklasse für jede siehe (dann hinzufügen alle Komponenten innerhalb der Unterklasse Konstruktor)
  • Erstellen einer ViewBuilder (für jede Art von siehe ), die dynamisch hinzufügt Komponenten zu einem "Standard" hinzufügt JPanel

Ich verwende in der Regel die erste Option, die mir logischer erscheint, aber ich verwende auch manchmal die zweite Möglichkeit, mit einem gewissen Maß an Anpassung: mein View Builder erstellt und speichert (als Felder) alle Komponenten, aber fügt sie zu einem bestehenden Panel (als Argument übergeben).

Ich verwende das zum Beispiel, um Komponentensätze wiederzuverwenden: Ich habe z. B. eine AddressView Klasse, die so funktioniert, und ich füge sie zweimal zu einer ContactView die Unterklassen JPanel einmal für Heimatadresse einmal für Büroadresse .

Man könnte sagen, dass ich auch die Unterklasse JPanel für AddressView und fügen Sie dann 2 Instanzen zu meinem ContactView Tafel. Der Grund, warum ich das nicht tue, ist, dass Swing LayoutManager s unterstützen nicht die Ausrichtung von Komponenten über verschiedene Panels hinweg, daher ist das resultierende ContactView-Panel in diesem Fall optisch nicht ansprechend.

0voto

Peter Tseng Punkte 12727

Meine allgemeine Faustregel lautet: Bevor Sie die Vererbung einsetzen, sollten Sie überlegen, ob eine Komposition sinnvoller ist.

Der Grund: Unterklassifizierung bedeutet in der Regel mehr Komplexität und Vernetzung, d. h. es ist schwieriger, etwas zu ändern, zu pflegen und zu skalieren, ohne Fehler zu machen.

Eine viel vollständigere und konkretere Antwort von Tim Boudreau der Sonne:

Häufige Probleme bei der Verwendung der Vererbung sind meiner Meinung nach folgende:

  • Unschuldige Handlungen können unerwartete Folgen haben - Das klassische Beispiel hierfür sind Aufrufe von überschreibbaren Methoden der Superklasse Konstruktor, bevor die Instanzfelder der Unterklassen initialisiert wurden. In einer perfekten Welt würde das niemand tun. Dies ist nicht eine perfekte Welt.
  • Sie verleitet Unterklassifizierer dazu, Annahmen über die Reihenfolge von Methodenaufrufen und dergleichen zu treffen. - Solche Annahmen sind in der Regel nicht stabil zu sein, wenn sich die Oberklasse im Laufe der Zeit weiterentwickeln kann. Siehe auch m und Kaffeekanne Analogie .
  • Die Klassen werden schwerer - Sie wissen nicht unbedingt, welche Arbeit Ihre Superklasse in ihrem Konstruktor verrichtet, oder wie viele verwenden wird. Das Konstruieren eines unschuldigen, vermeintlich leichtgewichtigen Objekts kann also viel teurer sein, als Sie denken, und das kann sich im Laufe der Zeit ändern, wenn die Superklasse sich weiterentwickelt
  • Sie begünstigt eine Explosion von Unterklassen . Das Laden von Klassen kostet Zeit, mehr Klassen kosten Speicherplatz. Das mag kein Problem sein, bis man es mit einer mit einer Anwendung in der Größenordnung von NetBeans zu tun hat, aber dort hatten wir echte Probleme, z. B. mit langsamen Menüs, weil die erste Anzeige eines Menüs eines Menüs ein massives Laden von Klassen auslöste. Wir haben dies durch den Wechsel zu deklarative Syntax und andere Techniken, aber auch das kostete Zeit zu beheben.
  • Das macht es schwieriger, Dinge später zu ändern. - Wenn Sie eine Klasse öffentlich gemacht haben, ist der Austausch der Superklasse es ist eine Entscheidung, die man trifft, wenn man den Code öffentlich gemacht hat, man ist verheiratet gebunden. Wenn Sie also die eigentliche Funktionalität Ihrer Klasse nicht ändern Superklasse nicht ändert, hat man viel mehr Freiheit, Dinge später zu ändern, wenn man verwenden, anstatt das, was Sie brauchen, zu erweitern. Nehmen Sie zum Beispiel, Unterklassenbildung von JPanel - das ist normalerweise falsch; und wenn die Unterklasse öffentlich ist, haben Sie nie die Möglichkeit, diese Entscheidung zu revidieren. Wenn es als JComponent getThePanel() aufgerufen wird, können Sie es immer noch tun (Hinweis: Stellen Sie Modelle für die darin enthaltenen Komponenten als API bereit).
  • Objekthierarchien lassen sich nicht skalieren (oder es ist viel schwieriger, sie nachträglich zu skalieren als im Voraus zu planen) - das ist das klassische "zu viele Schichten"-Problem Problem. Darauf gehe ich weiter unten ein, und wie das AskTheOracle-Muster lösen kann (obwohl es OOP-Puristen beleidigen könnte).

...

Meine Meinung dazu, was zu tun ist, wenn mit Vorsicht zu genießen ist:

  • Niemals Felder freilegen, außer Konstanten
  • Methoden müssen entweder abstrakt oder final sein
  • Keine Methoden aus dem Konstruktor der Oberklasse aufrufen

...

all dies gilt weniger für kleine als für große Projekte und weniger für private Klassen als für öffentliche

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X