Warum man nicht von JFrame/JDialog erben sollte: Unterschied zwischen den Versionen

Aus Byte-Welt Wiki
Zur Navigation springenZur Suche springen
K
K
 
(2 dazwischenliegende Versionen von einem anderen Benutzer werden nicht angezeigt)
Zeile 3: Zeile 3:
 
Es ist doch verwunderlich wie oft man so etwas hier sieht:
 
Es ist doch verwunderlich wie oft man so etwas hier sieht:
  
<code=java>public class Gui extends JFrame{
+
<syntaxhighlight lang="java">public class Gui extends JFrame{
 
   
 
   
 
     public Gui(){
 
     public Gui(){
 
         super("Toller titel");
 
         super("Toller titel");
 
         setDefaultCloseOperation(EXIT_ON_CLOSE);
 
         setDefaultCloseOperation(EXIT_ON_CLOSE);
         getContentPane().add(new JButton("sinnloser button"));
+
         getContentPane().add(new JButton("Out Of Order"));
 
         pack();
 
         pack();
 
         setVisible(true);
 
         setVisible(true);
 
     }
 
     }
}</code=java>
+
}</syntaxhighlight>
  
 
Sieht irgendwie bekannt aus, oder?
 
Sieht irgendwie bekannt aus, oder?
Und: Normalerweise würgt man die VM auch nicht mit <code=java>System.exit(0);</code=java> respektive <code=java>frame.setDefaultCloseOperation(EXIT_ON_CLOSE);</code=java> ab, sondern ruft <code=java>dispose()</code=java> auf.
+
Und: Normalerweise würgt man die VM auch nicht mit <syntaxhighlight lang="java">System.exit(0);</syntaxhighlight> respektive <syntaxhighlight lang="java">frame.setDefaultCloseOperation(EXIT_ON_CLOSE);</syntaxhighlight> ab, sondern ruft <syntaxhighlight lang="java">dispose()</syntaxhighlight> auf.
  
 
Tatsächlich ist der Code genauso furchtbar wie das hier:
 
Tatsächlich ist der Code genauso furchtbar wie das hier:
  
<code=java>public class Buchregal extends ArrayList<String>{
+
<syntaxhighlight lang="java">public class Buchregal extends ArrayList<String>{
 
   
 
   
 
     public Buchregal(){
 
     public Buchregal(){
Zeile 26: Zeile 26:
 
         add("Handbuch der Java Programmierung");
 
         add("Handbuch der Java Programmierung");
 
     }
 
     }
}</code=java>
+
}</syntaxhighlight>
  
 
Und mal ehrlich, wer würde auf die Idee kommen, so etwas anzustellen?
 
Und mal ehrlich, wer würde auf die Idee kommen, so etwas anzustellen?
Zeile 33: Zeile 33:
 
(zugegeben es ist kein schönes Buchregal das nur die Titel kennt)
 
(zugegeben es ist kein schönes Buchregal das nur die Titel kennt)
  
<code=java>public class Buchregal{
+
<syntaxhighlight lang="java">public class Buchregal{
 
   
 
   
 
     private ArrayList<String> buchtitel;
 
     private ArrayList<String> buchtitel;
Zeile 43: Zeile 43:
 
         buchtitel.add("Handbuch der Java Programmierung");
 
         buchtitel.add("Handbuch der Java Programmierung");
 
     }
 
     }
}</code=java>
+
}</syntaxhighlight>
  
 
Und genau so kann man auch mit der GUI-Klasse verfahren:
 
Und genau so kann man auch mit der GUI-Klasse verfahren:
  
<code=java>public class Gui{
+
<syntaxhighlight lang="java">public class Gui{
 
   
 
   
 
     private JFrame frame;
 
     private JFrame frame;
Zeile 58: Zeile 58:
 
         frame.setVisible(true);
 
         frame.setVisible(true);
 
     }
 
     }
}</code=java>
+
}</syntaxhighlight>
  
 
Nur was hat man jetzt eigentlich gemacht?
 
Nur was hat man jetzt eigentlich gemacht?
Zeile 69: Zeile 69:
 
'''Verwenden != Erweitern'''
 
'''Verwenden != Erweitern'''
  
<blockquote L-ectron-X>
+
 
Wenn wir von einer Klasse erben, sprechen wir auch davon, sie zu spezialisieren.
+
''Irgendwo im Forum hat das L-ectron-X mal recht treffend formuliert:''
Genauso, wie der Vater persönliche Eigenschaften an den Sohn vererbt, bekommt in der OOP eine erbende Klasse die Eigenschaften (Methoden und öffentliche Instanzvariablen) der Basisklasse (auch Superklasse) eingepflanzt. Die erbende Klasse muss aber für eine sinnvolle Anwendung der Vererbung weitere Eigenschaften erhalten, und/oder bestehende Eigenschaften spezialisieren.
+
Wenn wir von einer Klasse erben, sprechen wir auch davon, sie zu spezialisieren.
Genauso wie der Sohn vom Vater die Fähigkeit erbte, besonders schnell die 60m zu laufen, kann der Sohn nun aber auch noch die 100m besonders schnell laufen. Eine Fähigkeit, zu der der Vater nicht im Stande ist.</blockquote>
+
Genauso, wie der Vater persönliche Eigenschaften an den Sohn vererbt, bekommt in der OOP eine erbende Klasse die Eigenschaften (Methoden und öffentliche Instanzvariablen) der Basisklasse (auch Superklasse) eingepflanzt. Die erbende Klasse muss aber für eine sinnvolle Anwendung der Vererbung weitere Eigenschaften erhalten, und/oder bestehende Eigenschaften spezialisieren.
 +
Genauso wie der Sohn vom Vater die Fähigkeit erbte, besonders schnell die 60m zu laufen, kann der Sohn nun aber auch noch die 100m besonders schnell laufen. Eine Fähigkeit, zu der der Vater nicht im Stande ist.
  
  
Zeile 86: Zeile 87:
 
Ein Fall wo es tatsächlich Sinn macht von einer Grafikkomponente zu erben wäre dieser hier:
 
Ein Fall wo es tatsächlich Sinn macht von einer Grafikkomponente zu erben wäre dieser hier:
  
<code=java>public class PaintingPanel extends JPanel{
+
<syntaxhighlight lang="java">public class PaintingPanel extends JPanel{
 
   
 
   
 
     @Override
 
     @Override
Zeile 94: Zeile 95:
 
     }
 
     }
 
      
 
      
} </code=java>
+
} </syntaxhighlight>
  
 
Hier haben wir das JPanel tatsächlich erweitert, nämlich um eine hässliche kleine Linie die darauf gezeichnet wird  
 
Hier haben wir das JPanel tatsächlich erweitert, nämlich um eine hässliche kleine Linie die darauf gezeichnet wird  
Zeile 113: Zeile 114:
 
--[[Benutzer:Firephoenix|Firephoenix]] 19:18, 28. Aug 2013 (CET)
 
--[[Benutzer:Firephoenix|Firephoenix]] 19:18, 28. Aug 2013 (CET)
  
[[Kategorie:Java]]
 
 
[[Kategorie:Swing]]
 
[[Kategorie:Swing]]
 
[[Kategorie:Java Grundlagen]]
 
[[Kategorie:Java Grundlagen]]

Aktuelle Version vom 8. April 2018, 11:22 Uhr

Dieser Beitrag wurde von Firephoenix erstellt

Es ist doch verwunderlich wie oft man so etwas hier sieht:

public class Gui extends JFrame{
 
    public Gui(){
        super("Toller titel");
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        getContentPane().add(new JButton("Out Of Order"));
        pack();
        setVisible(true);
    }
}

Sieht irgendwie bekannt aus, oder?

Und: Normalerweise würgt man die VM auch nicht mit

System.exit(0);

respektive

frame.setDefaultCloseOperation(EXIT_ON_CLOSE);

ab, sondern ruft

dispose()

auf.

Tatsächlich ist der Code genauso furchtbar wie das hier:

public class Buchregal extends ArrayList<String>{
 
    public Buchregal(){
        add("Spiele programmieren mit Java");
        add("Spring im Einsatz");
        add("Handbuch der Java Programmierung");
    }
}

Und mal ehrlich, wer würde auf die Idee kommen, so etwas anzustellen?

Da schreibt man ein Buchregal, das 3 Buchtitel enthält, doch lieber so oder? (zugegeben es ist kein schönes Buchregal das nur die Titel kennt)

public class Buchregal{
 
    private ArrayList<String> buchtitel;
    
    public Buchregal(){
        buchtitel = new ArrayList<String>();
        buchtitel.add("Spiele programmieren mit Java");
        buchtitel.add("Spring im Einsatz");
        buchtitel.add("Handbuch der Java Programmierung");
    }
}

Und genau so kann man auch mit der GUI-Klasse verfahren:

public class Gui{
 
    private JFrame frame;
    
    public Gui(){
        frame = new JFrame("Toller titel");
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.add(new JButton("Out Of Order"));
        frame.pack();
        frame.setVisible(true);
    }
}

Nur was hat man jetzt eigentlich gemacht?

In den ersten 2 Beispielen haben wir Vererbung benutzt, um eine Klasse zu verwenden. Das Stichwort hier ist "verwenden" und nicht "erweitern"! Wir haben lediglich bestehende Funktionen der Klasse JFrame verwendet, aber keine neue Funktionalität hinzugefügt. Solange wir das nicht machen, besteht kein Grund von einer Klasse zu erben!

Verwenden != Erweitern


Irgendwo im Forum hat das L-ectron-X mal recht treffend formuliert:

Wenn wir von einer Klasse erben, sprechen wir auch davon, sie zu spezialisieren.
Genauso, wie der Vater persönliche Eigenschaften an den Sohn vererbt, bekommt in der OOP eine erbende Klasse die Eigenschaften (Methoden und öffentliche Instanzvariablen) der Basisklasse (auch Superklasse) eingepflanzt. Die erbende Klasse muss aber für eine sinnvolle Anwendung der Vererbung weitere Eigenschaften erhalten, und/oder bestehende Eigenschaften spezialisieren.
Genauso wie der Sohn vom Vater die Fähigkeit erbte, besonders schnell die 60m zu laufen, kann der Sohn nun aber auch noch die 100m besonders schnell laufen. Eine Fähigkeit, zu der der Vater nicht im Stande ist.


Wie es im Englischen schön heißt: composition over inheritance.

Wir benutzen daher möglichst Felder anstatt Vererbung.

Felder können jederzeit ausgetauscht werden, unser Bücherregal könnte zur Programmlaufzeit die ArrayList durch eine LinkedList ersetzen, (oder wenn der typ des Feldes nur Collection <String> wäre), sogar auf ein HashSet umsteigen. Benutzen wir dagegen Vererbung sind wir für alle Ewigkeit an die ArrayList gebunden und können zur Laufzeit nicht mehr davon weg. Außerdem wird die Vererbung Teil der API unserer Software, ein anderer Programmierer wird unsere Komponente z.B. auch wie eine ArrayList verwenden, auch hier haben wir keine Möglichkeit etwas zu Ändern ohne anderen Code zu gefährden. Halten wir dagegen solche Implementierungsdetails in privaten Feldern versteckt können wir zu jeder Zeit daran herumspielen, ohne das jemand etwas davon mitbekommen wird.

Ein Fall wo es tatsächlich Sinn macht von einer Grafikkomponente zu erben wäre dieser hier:

public class PaintingPanel extends JPanel{
 
    @Override
    protected void paintComponent(Graphics g){
        super.paintComponent(g);
        g.drawLine(3, 3, 6, 6);
    }
    
}

Hier haben wir das JPanel tatsächlich erweitert, nämlich um eine hässliche kleine Linie die darauf gezeichnet wird

Zu bemerken ist hier das @Override und der super-Aufruf. Es ist kein guter Stil, Methoden komplett zu überschreiben (z.B. würde das hier zu Zeichenfehlern im eigentlichen Panel führen), daher rufen wir zuerst die Methode der Superklasse auf. Weiterhin zeigt uns das @Override an, dass wir eine Methode der Superklasse überschrieben haben (und der Compiler meckert uns an wenn, wir sie falsch geschrieben haben -> gängige Fehlerquelle vermieden).

Generell also:
Wenn wir eine Klasse verwenden wollen, legen wir ein Feld mit dem Typ der Klasse an und verwenden das Feld.

Wenn wir eine bestehende Klasse um neue Funktionalität erweitern wollen, dann erben wir von der Klasse.

composition over inheritance


Fragen

Das Thema wurde nicht ausreichend behandelt? Du hast Fragen dazu und brauchst weitere Informationen? Lass Dir von uns helfen!

Wir helfen dir gerne!


Dir hat dieser Artikel gefallen? Oder Du hast Fehler entdeckt und möchtest zur Berichtigung beitragen? Prima! Schreibe einen Kommentar!

Du musst angemeldet sein, um einen Kommentar abzugeben.


--Firephoenix 19:18, 28. Aug 2013 (CET)