Vererbung "extends" umgehen mittels Objekterzeugung?!

chmbw

Mitglied
Hallo,

erstmal ein paar Zeilen zu meinem programmiertechnischen Hintergrund: Ich bin neu in der objektorientierten Programmierung, bin aber relativ gut bewandert in prozeduralen Programmierprachen insbesondere C. Da ich erst seit kurzem mit Java arbeite fällt es mir noch ein bisschen "schwer" die "Gedanken hinter der objektorientierung" zu verinnerlichen. Deshalb auch meine kleine Frage zu folgendem Codeschnipseln:

Angenommen ich habe zwei verschiedene Klassen.

Einmal:

Java:
public class Hauptfunktion {

	public static void main(String[] args) {

		fenster f = new Fenster();
	}
}

und meine zweite Funktion:

Java:
import javax.swing.JFrame;

public class Fenster {
	
	public Fenster() {
		JFrame fenster = new JFrame("Titel");		
		fenster.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
		fenster.setSize(256,256);
		fenster.setVisible(true);
	}
}

Mein Fenster erzeuge ich in der Klasse fenster indem ich einfach ein Objekt von der Klasse JFrame erzeuge und entsprechend über dieses Objekt auf die Funktionen zugreife. Ich kann fenster aber jetzt auch so schreiben:

Java:
import javax.swing.JFrame;

public class Fenster extends JFrame {
	
	public Fenster() {
		super("Titel");		
		setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
		setSize(256,256);
		setVisible(true);
	}
}

Beides funktioniert, jedoch würde ich gerne eine "Beurteilung" beider Methoden haben. Mit der ersten Version umgehe ich quasi die Möglichkeit der Vererbung, aber ich kann darin (noch) keinen Nachteil sehen (obwohl ich intuitiv der Meinung bin, Variante zwei müsste besser sein). Ich würde mich sehr freuen, wenn einer sich bereiterklären würde mir ein wenig weiter zu helfen und mir das ein wenig erläutern könnte!

Viele Grüße

EDIT: Klassennamen groß geschrieben
 
Zuletzt bearbeitet:

Eldorado

Bekanntes Mitglied
Also ich gehe da eigentlich nach folgender Faustregel vor: Wenn du einer Klasse keine zusätzlichen Funktionen geben willst, musst du diese auch nicht erweitern.
In diesem Fall benutzt du, wie es meistens der Fall ist, nur die Methoden von JFrame, weswegen du es eigentlich auch nicht erweitern musst. Es bringt dir einfach keinen Vorteil und ist meiner Meinung auch kein sonderlich guter Stil.

Und Klassen schreibt man groß!
 
G

gman

Gast
Ich würde sagen das in diesem Fall die zweite Variante wirklich besser ist, da deine Klasse "Fenster" ja
auch "ein JFrame ist". In solchen Fällen ergibt dann die Vererbung Sinn.

Das erste Beispiel ist mehr nach dem Motto: "Ziehe Komposition der Vererbung vor."
Kein Problem wenn dir das jetzt noch nichts sagt. Der Satz will sagen das man auch einfach ein Objekt
einer potentiellen Superklasse (in diesem Fall JFrame) benutzt anstatt sich mit der Klasse in eine
Vererbungshierarchie einzugliedern.

Übrigens gilt bei Java die Konvention das man Klassen mit einem Grossbuchstaben anfängt. Variablen
und Objekte von Klassen fangen mit einem Kleinbuchstaben an.
 

chmbw

Mitglied
Hallo,

erstmal vielen Dank für eure schnellen Antworten. Aus euren (widersprüchlichen) Aussagen ziehe ich, dass es im Endeffekt eine Frage des persönlichen Stils ist welche Variante ich verwende.

Wenn ich meinem Fenster jetzt noch zusätzlich ein paar Buttons, ein Textfeld oder ähnliches hinzufügen wollen würde, der ganze Konstruktor von Fenster also um einiges komplexer wird, würde es dann Variante zwei mehr Sinn machen, weil ich ja mehrere Klassen zusammenwerfe und "JFrame" ja somit auch erweitere


Viele Grüße

PS:
Danke für den Hinweis mit den Klassennamen, ich habe es angepasst :)
 
S

Spacerat

Gast
Das Beispiel ist ein wenig ungünstig gewählt. Hättest du dort einen JPanel genommen und einen solchen in eine Klasse MyPanel komponiert (wie sich des anhört... lol) würdest du spätestens dann ein Problem haben, wenn du MyPanel einem JFrame hinzufügen willst, weil MyPanel auf die Art rein gar nichts von einer JComponent hat bzw. erbt. Hättest du hingegen JPanel erweitert, ginge dies recht einfach mit "JFrame.getContentPane().add(MyPanel)".
 

Eldorado

Bekanntes Mitglied
@Spacerat: Und was wäre das Problem in der Klasse eine Methode
Code:
getPanel()
einzufügen, die das Panel mit den geaddeten Komponenten zurückgeben würde?

Code:
JFrame.getContentPane().add(myPanel.getPanel())

Also ich finde das nicht wirklich ein Argument. Aber das ist scheinbar wirklich einfach der eigene Stil.
 
S

Spacerat

Gast
@Eldorado: Da sagst du was... Ist jetzt zwar mehr oder weniger OT aber was soll's. Zugegeben; Ein Argument für Vererbung ist es nicht. Wer auf die Art mit Kompositing klar kommt, soll dies tun. Auf jeden Fall wäre es aber ein Argument für ein "ComponentInterface", gegen welches man seine Komponenten codet. Dann würde man nicht mehr so unter der Qual der Wahl ob Kompositing oder Vererbung stehen, weil man einfach nur noch ein Interface implementieren müsste. Wenn nun alle Container statt einer (letztendlich) "java.awt.Component" dieses Interface erwarten würden, müsstest du dir um deine "getPanel()"-Methode auch keine Gedanken mehr machen. Aber btw.: Dein "Stil" ist genau das "Problem", das der TS bekommen hätte ;)
Java:
public interface ComponentInterface
{
  void update(Graphics g);
  void paint(Graphics g);
  //... alles was zun Zeichnen einer Component benötigt wird.
}

public class Container
extends Component
{
  // ersetzt java.awt.Container

  void add(ComponentInterface comp)
  {
    // ersetzt java.awt.Container.add(Component comp)
  }
}

public class MyPanelInherit
extends JPanel
implements ComponentInterface
{
  // die InterfaceMethoden müssen nichtmal mehr implementiert werden
}

public class MyPanelComposite
extends IrgendwasOhneComponent
implements ComponentInterface
{
  private final JPanel panel;

  public MyPanelComposite()
  {
    panel = new JPanel();
  }

  public void update(Graphics g)
  {
    panel.update(g);
  }

  public void paint(Graphics g)
  {
    panel.paint(g);
  }
}
Ohne vorwitzig wirken zu wollen: Ich hoff' so wird verstanden wie ich's meine ;)
 
Zuletzt bearbeitet von einem Moderator:

chmbw

Mitglied
Hi,

ich bin mir leider nicht sicher ob ich dich richtig verstanden habe... Ich habe nochmal ein wenig rumgespielt und folgenden Code gebastelt:

Java:
import javax.swing.JFrame;

public class Hauptfunktion {

	public static void main(String[] args) {

		//new Fenster();
		//new FensterExtendFrame();
		
		JFrame frame = new JFrame("Extends JPanel");
		frame.add(new fensterExtendPanel() );
		
		frame.pack();
		frame.setVisible(true);
	}
}

dazu drei verschiedene Klassen:

Java:
import javax.swing.JFrame;
import javax.swing.JButton;
import javax.swing.JPanel;

public class Fenster{
	
	public Fenster() {
		JFrame frame = new JFrame("Kein extend");		
		JButton button1 = new JButton("drück mich");
		JPanel panel1 = new JPanel();
		
		frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
		frame.setSize(256,256);
		frame.setVisible(true);
		
		panel1.add(button1);
		frame.add(panel1);
		
		frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
		frame.pack();
		frame.setVisible(true);
	}
}

Java:
import javax.swing.JFrame;
import javax.swing.JButton;
import javax.swing.JPanel;


public class FensterExtendFrame extends JFrame{

	public FensterExtend()
	{
		super("Extend JFrame");
		this.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
		
		JButton button = new JButton("drück mich");
		JPanel panel = new JPanel();
		
		panel.add(button);
		add(panel);
		
		this.pack();
		this.setVisible(true);
	}
	
}

Java:
import javax.swing.JButton;
import javax.swing.JPanel;


public class FensterExtendPanel extends JPanel{

	public FensterExtendPanel()
	{
		JButton button = new JButton("drück mich");
		this.add(button);
	}
	
}

Alle drei Versionen funktionieren bei mir ohne Proble, ich verstehe den Einwand

Das Beispiel ist ein wenig ungünstig gewählt. Hättest du dort einen JPanel genommen und einen solchen in eine Klasse MyPanel komponiert (wie sich des anhört... lol) würdest du spätestens dann ein Problem haben, wenn du MyPanel einem JFrame hinzufügen willst, weil MyPanel auf die Art rein gar nichts von einer JComponent hat bzw. erbt. Hättest du hingegen JPanel erweitert, ginge dies recht einfach mit "JFrame.getContentPane().add(MyPanel)".

dann wohl leider nicht wirklich. Wäre über eine Aufklärung sehr dankbar :)

Viele Grüße
 

Volvagia

Top Contributor
Er meint wohl, wenn MyPanel dann ein Wrappler für das Panel wäre. Ich würde dir davon abraten, für soetwas zu vererben. Max. von JFrame, da du in die Klasse die Main packen und in dem Konstruktor die GUI erzeugen kannst. Das wird recht oft gemacht. Aber dabei erhöht sich allgemein die Klassenanzahl so, dass du am Ende nicht mehr so gut weißt, was wo gemacht wird, und es eigendlich verwirrt. Außerdem erhöhen sich so die Abhängigkeiten, statt wenn die Instanzen in den selben Methoden instanziert werden und so direkt kommunizieren können. Deshalb würde ich mir bei jeder Klasse genau überlegen, ob es sich auszahlt.
 

chmbw

Mitglied
Danke für den Beitrag! Mein "Problem" ist, dass ich noch nicht wirklich "firm" bin was objektorientierung angeht...So hat sich ja auch die Frage ergeben, was ich wie am Besten verwenden soll, bzw. was unter welchen Umständen genutzt werden soll.
 
S

Spacerat

Gast
@TS: Denn möchte ich dich mal nicht dumm sterben lassen ;)

Im Prinzip geht's darum, dass die Windowtoolkits (AWT und Swing) meiner Meinung nach einen entschiedenden Designfehler haben. Alle Container dieser beiden Toolkits (JFrame, Frame, JPanel, Panel usw.) haben die gleichnamige Klasse aus "java.awt" als Muterklasse, "java.awt.Container" selbst erweitert "java.awt.Component". Von "java.awt.Container" erben sie Methoden um dem Container weitere Komponenten hinzufügen zu können, welche allesamt eine "java.awt.Component" als Parameter erwarten.

Deswegen hat man nun genau 2 Möglichkeiten, seinen Containern eigene Komponenten hinzuzufügen:
1. Man erweitert mit eigenen Kontainern mindestens die Klasse Component, was den Vorteil hat, dass man z.B. "jFrame.getContentPane().add(myComponent)" schreiben kann aber auch den Nachteil birgt, dass man keine weitere Klasse erweitern kann, denn Mehrfachveerbung ist in Java nunmal nicht möglich.
2. Man macht es wie Eldorado und fügt seiner Kompomente die Methode "Component getComponent()" hinzu, was nun den Nachteil hat, dass man bei jedem hinzufügen zu einem Kontainer z.B. "jFrame.getContentPane().add(myComponent.getComponent())" schreiben muß. Der Vorteil aber ist; eine Solche Komponente kann etwas ganz anderes ausserhalb der Componenthierarchie erweitern.

Würde ein Kontainer nun ein Interface (ComponentInterface) als Minimum akzeptieren, würde es genügen, dieses bei seinen Komponenten zu implementieren und man hätte weiterhin die Möglichkeit etwas weit ausserhalb der Componentkette damit zu erweitern. Kurz gesagt: Bei Möglichkeit 2 würde diese zusätzliche Methode "getComponent()" wieder wegfallen.

Im übrigen: Am gängigsten ist natürlich Möglichkeit 1, aber wie man sieht... es gibt ausnahmen. Nicht wahr Eldorado? ;)
 
Zuletzt bearbeitet von einem Moderator:

chmbw

Mitglied
Danke für die ausführliche Erklärung. Wenn ich alles nochmal zusammenfasse, dann heißt das, dass ich mit dem Erben von JFrame ja gar nicht so schlecht fahre, bzw. mir überlegen sollte ob ich wirklich erben muss und nicht einfach über ein Objekt mein GUI aufbaue.

Ich bin mir jedoch nicht sicher, ob ich die zweite Möglichkeit mit getComponent komplett verstanden habe, wobei das jedoch auch auf die gegenwärtige Uhrzeit zurückzuführen sein kann ;)
Ich muss mir das morgen nochmal genauer ansehen. Vielen Dank!
 

Volvagia

Top Contributor
Ich nehme eigendlich einen 3. Weg.
Ich teile meine Projekte meistens in Subsysteme auf. Dazu beginne ich irgendwo (Mainmethode, irgend eine Build-Klasse, bei meinen Projektplaner muss ich von einer JInternalFrame-Subklasse erben, da dort zum Anzeigen noch recht viel im Hintergrund gemacht werden muss, wofür ich sie an eine Klasse zum starten übergebe) usw.
Dort erzeuge ich alle Komponenten wie JLabels, JPanels, JButtons usw. Diesen adde ich direkt anonyme Listener. Wenn die Vorgänge nur kurz sind, z. B. einen Labeltext verändern schreibe ich sie direkt hinein. Bei länger dauernden aber Codemäßig sehr kurzen Vorgängen starte ich schon mal direkt darin einen Thread, z. B. wenn ich auf eine Serverantwort warte, was schon mal dauern kann.
Bei recht langen Vorgängen oder Hintergrundfunktionen, die irgendwann Rückmeldungen tätigen schreibe ich mir Threadklassen und implementiere in den meisten Fällen einen eigenen kleinen anonymen Listener.

Das reicht bei mir bisher vollkommen. So entsteht aus den GUI-Methoden/-Klasse und den Threads ein geschlossenes System.
 

oopexpert

Mitglied
Objektorientierung lebt von Struktur, Objektkollaboration und Polymorphie. Letzteres ist insbesondere bei AWT und Swing Komponenten nur durch Vererbung möglich. Dies sollte man unbedingt anstreben, wenn man wiederverwendbare Komponenten entwickeln möchte. Dann heißt es erben, überschreiben, extendieren. Das Vorgehen wiefolgt zeugt tatsächlich von wenig OO und mehr von prozeduraler Programmierung:
Java:
... main ...
JFrame myJFrame = new JFrame();
JPanel myPanel = new JPanel();
JButton myButton = new JButton();
myPanel.add(myButton);
myJFrame.getContentPane().add(myPanel);
...

Ein JFrame würde ich IMMER extendieren. Alles andere würde auch dem Geheimnisprinzip widersprechen.

Bei anderen Komponenten würde ich tatsächlich nur dann extendieren, wenn sie komplexe Funktionalität kapseln. Solche komplexen Komponenten werden dann wiederverwendbar, wie z.B. Master-Detail-Ansichten, JComboBox bei der man zusätzlich mit 2 Buttons durch die Elemente navigieren kann oder Komponenten die eine kaskadierende Funktion haben (Combobox 3 ist abhängig von CB 2, CB 2 ist abhängig von CB 1.

... Würde ein Kontainer nun ein Interface (ComponentInterface) als Minimum akzeptieren, würde es genügen, dieses bei seinen Komponenten zu implementieren und...
Absolut korrekt, hier haben die Jungs von AWT absolut gefuscht, weil sie kein Interface anbieten.
 
B

bygones

Gast
hab nicht alles gelesen - aber ich stimme Eldorado hier zu - und widerspreche dem "ooexperten" hier voellig (es ist falsch zu sagen dass man wiederverwendbarkeit nur durch Vererbung bekommen wuerde und das Delegation per se zu prozedualen Code fuehrt)

Ein JFrame würde ich IMMER extendieren. Alles andere würde auch dem Geheimnisprinzip widersprechen
den satz versteh ich nicht, was fuer ein Geheimnisprinzip ?... und du sagst es selbst im Konjunktiv.

Vererbung wird meist nicht benutzt, weil es sich um Vererbung handelt, sondern weil man damit manches einfacher haben kann - also aus Faulheit.

natuerlich ist es einfacher MyPanel von JPanel erben zu lassen, weil man dann diesen einfach ohne Umwege in Frames packen kann usw.

Das Problem ist aber, man zieht sich eine Unzahl von Methoden in seine Klasse, die man vielieicht nicht will.

Wenn man zb eine addMyComponent Methode hat, die die komponenten bestimmt anordnet, kann der Verwender bei Vererbung diese leicht mit JPanel#add etc aushebeln. Ausserdem sieht der Verwender unzaehlige Methoden der gesamten Vererbungshierarchie und nicht die relevanten API Methoden der Klasse.

Beste bsp sind Stack und Properties aus dem JDK... voellig verhunzt durch Vererbung

Daher - Vererbung niemals aufgrund von Faulheit nutzen... Delegation hat vor Vererbung immer vorrang
 
Zuletzt bearbeitet von einem Moderator:
V

vanny

Gast
Ich muss bygones Recht geben,

zBsp. die Aussage, das man JFrame immer vererben sollte impliziert ja geradezu, dass diese Klasse dann für nichts anderes mehr zuständig ist. (Wenn dem wirklich so ist, kann man bei der Vererbung nicht von Faulheit sprechen).
In vielen Fällen bietet es sich aber an noch viel mehr Funktionalität in diese Klasse zu bringen und spätestens dann sollte man versuchen die Vererbung zu vermeiden und den JFrame klar von anderen Bestandteilen trennen.
Das gilt dann natülich auch für alle anderen Klassen, die mehr als nur einen Job erledigen.
 
Zuletzt bearbeitet von einem Moderator:

oopexpert

Mitglied
hab nicht alles gelesen - aber ich stimme Eldorado hier zu - und widerspreche dem "ooexperten" hier voellig (es ist falsch zu sagen dass man wiederverwendbarkeit nur durch Vererbung bekommen wuerde und das Delegation per se zu prozedualen Code fuehrt)

1. Die Wiederverwendbarkeit von AWT Komponenten ist nur durch extends zu realisieren, weil keine Schnittstellen (implements) angeboten werden. Alle anderen Bereiche bleiben unberührt, und Komposition mit Delegation hat Vorrang vor Vererbung.

...den satz versteh ich nicht, was fuer ein Geheimnisprinzip ?... und du sagst es selbst im Konjunktiv...

2. Geheimnisprinzip und Kapselung: Wenn ich ein MyJFrame instanziiere, sollte es selber wissen, welche anderen Elemente es instanziieren muss (Kapselung). Des Weiteren interessiert den Aufrufer nicht, wie der MyJFrame dies tut (Geheimnisprinzip).


Nachsatz:
Im GUI-Bereich hat man fast eh nur Beans, deshalb kenne GUI-Entwickler keine Geheimnisse ;)
 
B

bygones

Gast
2. Geheimnisprinzip und Kapselung: Wenn ich ein MyJFrame instanziiere, sollte es selber wissen, welche anderen Elemente es instanziieren muss (Kapselung). Des Weiteren interessiert den Aufrufer nicht, wie der MyJFrame dies tut (Geheimnisprinzip).
sorry - du meinst Kapselung erreicht man ueber Vererbung ? mhm...
und du hast recht, wenn man MyJFrame instanziiert, sollte er wissen was er tun muss, nicht der Verwender, aber auch das ist kein Grund fuer vererbung.
Auch stimme ich zu, dass der Verwender es nicht interessieren soll, wie MyJFrame sich zusammenbaut etc, ebenso soll der Verwender da auch nicht reingreifen koennen.

wenn du von Jframe erbst oeffnest du das Geheimnis deiner Klasse und laesst alle von aussen voll reingreifen. Erst durch delegation schaffst du die kapselung und geheimhaltung.

Somit stimme ich dir in deiner Argumentation zu, deine Schlussfolgerung dies aber durch Vererbung zu erreichen ist leider voellig falsch.
 
S

Spacerat

Gast
@bygones, @oopexpert: Eigentlich sind wir uns doch alle einig... Im Falle diverser Java-GUI-Komponenten trifft es zu, wenn bygones sagt, dass man Kapselung nicht durch Veerbung erreicht. Aber eigentlich sollte es doch so sein oder nicht. Daraus ergibt sich doch auch der klar erkennbare Designfehler in diesen Komponenten. Es fehlt halt das Interface um aus seiner Irgendwas-Klasse ein GUI-Element zu machen. Innerhalb dieses Interfaces macht dann Delegation wieder Sinn, welche man andernfalls halt nach "draussen" tragen muß, wo sie wieder komplett fehl am Platze ist. Von daher hat oopexpert in der Hinsicht recht, dass man doch eher Veerbung anstreben oder besser stets gegen Schnittstellen programmieren sollte, denn innerhalb einer solchen kann man, wie oben gezeigt, vollkommen diskret (geheim) delegieren ;).
 
Zuletzt bearbeitet von einem Moderator:

bERt0r

Top Contributor
Es ist zwar schon spät, aber irgendwie redet ihr hier gewaltigen blödsinn. Euren kleinlichen Streigt über Sinn von Vererbung/Delegation verstehe ich nicht. Natürlich macht es Sinn, von JFrame zu erben, wenn die Klasse eine GUI darstellen will. Wenn man extra wieder eine Funktion "getPanel()" oder "getFrame()" in seiner Klasse erstellt ändert das rein gar nichts an Änderbarkeit oder Kapselung der Daten. Man kann diese Instanz die man durch die get Funktion erhält genause manipulieren wie eine Klasse die von JFrame erbt. Viel eher hat man durch Vererbung genau dann die Kontrolle, wenn man von der Klasse erbt (z. B.: auf add nicht zu reagieren), indem man Methoden überschreibt.
 
B

bygones

Gast
@Spacerat:
ich stimme zu bzgl der fehlenden Interfaces und dem darausfolgenden Designfehlers. Und natuerlich, wenn sich der Verwender stets an die Schnittstelle haelt (sehen wir JFrame als eine), so waere das noch eher akzeptabel. Dennoch wird Vererbung zu oft zu falsch genutzt.

@bertor
deine aussage zeigt mir eher dass du weder delegation noch kapselung verstehst, somit ist deine Aussage nichtssagend und falsch
 

bERt0r

Top Contributor
Ich habe mich vor allem auf diesen Satz bezogen:
Wenn man zb eine addMyComponent Methode hat, die die komponenten bestimmt anordnet, kann der Verwender bei Vererbung diese leicht mit JPanel#add etc aushebeln. Ausserdem sieht der Verwender unzaehlige Methoden der gesamten Vererbungshierarchie und nicht die relevanten API Methoden der Klasse.

Bei einem Konstrukt wie
Java:
JFrame.getContentPane().add(myPanel.getPanel())
kann man mit dem Panel, das man durch getPanel aus deiner tollen Kapsel erhält, noch immer anstellen was man will.
Wenn man kapseln will, darf das Panel nicht nach aussen gegeben werden, das heisst, du musst in deiner Kapsel die gesamte Oberfläche des Panels erstellen bzw. extra Funktionen schreiben, mit denen du es dann bearbeitest. Also jede menge zusätzlicher Aufwand.

Wenn deine Klasse von JPanel erbt und du möchtest, dass deine Klasse immer PreferredSize (100,100) hat, überschreibst du einfach die Methode getPreferredSize so, dass sie immer eine 100,100 Dimension zurückgibt, und niemand kann daran mehr etwas ändern, es sei denn man extended deine Klasse erneut und überschreibt die Funktion nochmal.
 
B

bygones

Gast
Bei einem Konstrukt wie
Java:
JFrame.getContentPane().add(myPanel.getPanel())
kann man mit dem Panel, das man durch getPanel aus deiner tollen Kapsel erhält, noch immer anstellen was man will.
Wenn man kapseln will, darf das Panel nicht nach aussen gegeben werden, das heisst, du musst in deiner Kapsel die gesamte Oberfläche des Panels erstellen bzw. extra Funktionen schreiben, mit denen du es dann bearbeitest. Also jede menge zusätzlicher Aufwand.

Wenn deine Klasse von JPanel erbt und du möchtest, dass deine Klasse immer PreferredSize (100,100) hat, überschreibst du einfach die Methode getPreferredSize so, dass sie immer eine 100,100 Dimension zurückgibt, und niemand kann daran mehr etwas ändern, es sei denn man extended deine Klasse erneut und überschreibt die Funktion nochmal.
es waere auch toericht bei myPanel.getPanel() einen JPanel zurueckzugeben. aufgrund der fehlenden Interfaces sollte man die hoechstmoegliche Ebene nehmen. Bei einer JComponent zb verringert man schon die Problematik um einiges - kannst schafft man es natuerlich in dieser Konstruktion nicht.

Aber bei Vererbung weniger Aufwand ? komm... um eine gute Kapselung zu erreichen muesstest du bei JPanel zig methoden ueberschreiben. Bei Delegation ist dieser aufwand wesentlich geringer.
Auch die argumentation "eine vollstaendige kapselung erreicht man nicht, daher ists mit Vererbung einfacher" lass ich nicht gelten.

Mir ist klar, dass swing leider kein gutes bsp ist um dies zu verdeutlichen, aber trotzdem vererbung als besseres heilmittel darzustellen ist falsch.
 

Empire Phoenix

Top Contributor
Vererbung ist insbesondere dann sinvoll, wenn man bestehende funktionalität erweitern will, ohne dass alle benutzenden Klassen geänder werden sollen. Sagen wir mal ein JFrame das warum auch immer alle add(Component) loggen soll.
Dann muss man nur das jFrame erweitern, und die add methode entsprechend mit logging überschreiben , danach dann super aufrufen. OHNE das das gesammte programm geändert werden muss. Mit Delegation wäre das zwar auch lösbar, würde aber viele änderungen nach sich ziehen, da das Object ja dann selber kein JFrame mehr ist.
 
B

bygones

Gast
Vererbung ist insbesondere dann sinvoll, wenn man bestehende funktionalität erweitern will, ohne dass alle benutzenden Klassen geänder werden sollen. Sagen wir mal ein JFrame das warum auch immer alle add(Component) loggen soll.
Dann muss man nur das jFrame erweitern, und die add methode entsprechend mit logging überschreiben , danach dann super aufrufen. OHNE das das gesammte programm geändert werden muss. Mit Delegation wäre das zwar auch lösbar, würde aber viele änderungen nach sich ziehen, da das Object ja dann selber kein JFrame mehr ist.
Es gibt nur nicht 1 add Methode sondern 5, d.h. man darf schonmal keine vergessen. Haette man Delegation von anfang an genommen kannst du funktionalitaet erweitern wie man will ohne nach aussen etwas zu tun (wir bringen hier auch nun durcheinandern, ob ich nun eine Klasse fuer JFrame habe oder eine Klasse fuer JPanel).
Bei Vererbung bindet man sich an die Implementierung (auch wenn, wie schon hier immer gesagt wurde, Swing ein ungutes bsp ist) - Aenderungen sind im Nachhinein durch die veroeffentliche API schwierig bis unmoeglich. Gaebe es nun in einer neuen Version den SuperJFrame, kann man nicht umstellen.
Gaebe es in einer neuen Version die 6. add methode hat man wieder ein Problem.

Ich weiss dass v.a. bei Swing durch die fehlenden interfaces eine richtige Kapselung nicht machbar ist, aber Vererbung ist leider nicht immer der richtige Weg um ein gutes Projekt zu erstellen.

The extends keyword is evil; maybe not at the Charles Manson level, but bad enough that it should be shunned whenever possible
 

bERt0r

Top Contributor
es waere auch toericht bei myPanel.getPanel() einen JPanel zurueckzugeben. aufgrund der fehlenden Interfaces sollte man die hoechstmoegliche Ebene nehmen. Bei einer JComponent zb verringert man schon die Problematik um einiges - kannst schafft man es natuerlich in dieser Konstruktion nicht.

Aber bei Vererbung weniger Aufwand ? komm... um eine gute Kapselung zu erreichen muesstest du bei JPanel zig methoden ueberschreiben. Bei Delegation ist dieser aufwand wesentlich geringer.
Auch die argumentation "eine vollstaendige kapselung erreicht man nicht, daher ists mit Vererbung einfacher" lass ich nicht gelten.

Mir ist klar, dass swing leider kein gutes bsp ist um dies zu verdeutlichen, aber trotzdem vererbung als besseres heilmittel darzustellen ist falsch.

Und wenn du ein Object zurückgibst, ich kann sogar mit instanceof abragen was es ist und je nachem herumcasten und damit Unfug treiben. Eine Kapsel gibt den Gegenstand den sie kapselt nicht nach außen, das ist widerspricht dem Sinn der Kapselung.

Ich weis nicht warum die Java-Gurus kein Interface für Components erstellt haben, schätze aber, das liegt daran dass es sehr viele Grundfunktionen gibt, die ein GUI Element implementieren muss. Ausserdem sollte man View und Businesslogic ja sowieso trennen, darum habe ich persönlich jedenfalls noch nie das Bedürfnis gehabt, Mehrfachvererbung bei einem GUI Element anwenden zu müssen.
 
S

Spacerat

Gast
Es gibt nur nicht 1 add Methode sondern 5.
Auch dieses ist wieder ein sehr schlechtes Beispiel. Alle diese add-Methoden landen in einer weiteren Methode
Java:
  protected void addImpl(Component comp, Object constraints, int zindex) {
    // ...java implementation
  }
Diese kann man natürlich stellvertretend für all diese und folgende add-Methoden überschreiben.

Und wenn du ein Object zurückgibst, ich kann sogar mit instanceof abragen was es ist und je nachem herumcasten und damit Unfug treiben. Eine Kapsel gibt den Gegenstand den sie kapselt nicht nach außen, das ist widerspricht dem Sinn der Kapselung.
Sorry? Des versteh' ich nicht ganz. Du kannst mit instanceof höchstens feststellen, ob des Object eine Instanz der geforderten Klasse ist. Mit ellenlangem Code herausfinden, ob es sich dabei um eine von dir verwenbare Klasse handelt, wäre Unfug genug. Bei Erfolg, kann man sich den Unfug, den man dann mit diesem Objekt noch so treiben möchte regelrecht sparen. Bei Monty Python hättest da echt mehr zu lachen ;)
 
Zuletzt bearbeitet von einem Moderator:

bERt0r

Top Contributor
Ein Beispiel, ich will in JLabel erstellen, in dem immer "Hallo Welt" steht. 2 Möglichkeiten:

Java:
class MyLabelKapsel
{
JLabel label;
public MyLabelKapsel()
{
label=new JLabel("Hallo Welt");
}

public JComponent getComponent()
{
return label;
}
}
Java:
class MyLabel extends JLabel
{
public MyLabel()
{
super("Hallo Welt");
}
public String getText()
{
return "Hallo Welt";
}
}

Bei der oberen Variante kannst du jetzt aber immer noch schreiben
Java:
((JLabel)new MyLabelKapsel().getComponent()).setText("Tschüss Welt");
Bei der unteren Variante wird dir das Label, was du auch machst immer "Hallo Welt" anzeigen, es sei denn du extendest das MyLabel erneut.

Sorry? Des versteh' ich nicht ganz. Du kannst mit instanceof höchstens feststellen, ob des Object eine Instanz der geforderten Klasse ist. Mit ellenlangem Code herausfinden, ob es sich dabei um eine von dir verwenbare Klasse handelt, wäre Unfug genug. Bei Erfolg, kann man sich den Unfug, den man dann mit diesem Objekt noch so treiben möchte regelrecht sparen. Bei Monty Python hättest da echt mehr zu lachen
Wenn du dir Möglichkeiten von instanceof nicht einleuchten, wie wäre is gleich mit Reflection? Du kannst absolut alles aus der Instanz auslesen, verändern bzw. aufrufen, auch wenn du nicht genau weisst welche Klasse es ist. Darum heisst es in der Datenkapselung "'Durchgriff' von der Anwendung zur konkreten Darstellung wird verboten bzw. verhindert." und mehr wollte ich eigentlich auch gar nicht demonstrieren. Beurteilen, in wiefern es nämlich Sinn macht die Gui auf diese Art und Weise abzukapseln, traue ich mir nicht :)
 
S

Spacerat

Gast
Also die Möglichkeiten von instanceof leuchten mir schon ein. Für dein Beispiel etwa so:
Java:
JComponent comp = myLabelKapsel.getComponent();
if(comp instanceof Label) { // möglicherweise sinnlose Abfrage. Hier muß gezielt nach der Klasse gefragt werden.
  // Zeit um erneut Unfug zu treiben
  ((Label) comp).setText("Unfug"); // funktioniert durchaus. Die Klasse Label ist aber geraten.
} else if(wasAuchImmer) {
  // möglicherweise noch mehr quatsch, der sich per else if so oft man möchte widerholen lässt.
} else {
  // tja... was nun? comp hat ja gar keine setText-Methode. War denn der sch... Aufwand nun für die Katz? Ja natürlich. Hast was anderes erwartet?
}
Was ich damit sagen will: Das Geheimnis der Kapselung bleibt durch die Rückgabe einer JComponent durchaus gewart, weil man schon derbe mit instanceof raten müsste, welche Klasse dabei wirklich rauskommt. Schon allein dieses Gerate ist und bleibt Unfug.
 
B

bygones

Gast
ich denke jedem ist klar dass wenn man um teufel komm raus "boeses" anstellen will man immer es schaffen kann - aber das ist unsinnig zu diskutieren.

Wenn jemand eine API per Delegation veroeffentlich ist die Intension eindeutiger als per Vererbung. Man sollte sich natuerlich immer an die Intension einer API halten und sie nicht umgehen. Im Falle Delegation ist dies besser kommuniziert meiner Meinung nach.
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
mrStudent <? extends T> und <? super T> Java Basics - Anfänger-Themen 1
berserkerdq2 Größter unterschied von extends thread und implements runnable? Java Basics - Anfänger-Themen 2
N Variabel in eine class mit "extends JLabel" übertragen Java Basics - Anfänger-Themen 2
J extends Problem Java Basics - Anfänger-Themen 2
N extends und super vs new object Java Basics - Anfänger-Themen 4
JavaTalksToMe Extends/Implements Frage Java Basics - Anfänger-Themen 3
D public ArrayList(Collection<? extends E> c); Java Basics - Anfänger-Themen 2
CptK Interface Klasse Frame (extends JFrame) aus anderer Klasse schließen Java Basics - Anfänger-Themen 7
J Implements und Extends Java Basics - Anfänger-Themen 5
C Was macht `public class ClassName<T extends Comparable<T>>`? Java Basics - Anfänger-Themen 14
J Compiler-Fehler Fehler bei Vektor (E extends Object declared in class Vector) Java Basics - Anfänger-Themen 9
M mehrere extends? Java Basics - Anfänger-Themen 19
J doppelname nach schlüsselwort extends Java Basics - Anfänger-Themen 4
V Was bewirkt das Schlüsselwort extends in Verbindung mit class bzw. public class ? Java Basics - Anfänger-Themen 2
T extends und implements Java Basics - Anfänger-Themen 11
Crazynet 2 extends Java Basics - Anfänger-Themen 22
S Wrapper Klasse und extends Java Basics - Anfänger-Themen 2
W Methoden Rückgabedatentyp java.util.Map<java.lang.String,? extends ...> Java Basics - Anfänger-Themen 4
R Vererbung Übergabe von Variablen der Superklasse an Subklasse mit "extends" Java Basics - Anfänger-Themen 5
K Erste Schritte Extends Implements Java Basics - Anfänger-Themen 4
S Threads Thread wenn extends schon vergeben Java Basics - Anfänger-Themen 8
vandread Java Wildcards - Wann super wann extends? Java Basics - Anfänger-Themen 2
F Anfängerfrage zu extends Java Basics - Anfänger-Themen 12
B addAll(Collection<? extends E> c) Java Basics - Anfänger-Themen 9
T Input/Output StructuredFileReader extends BufferedReader Java Basics - Anfänger-Themen 6
K Erste Schritte extends vererbung Java Basics - Anfänger-Themen 15
P Class<? extends Entity> Array Java Basics - Anfänger-Themen 9
A final und extends Java Basics - Anfänger-Themen 14
Y Threads extends Thread oder implements Runnable Java Basics - Anfänger-Themen 10
L Implements<-->extends und Interface Java Basics - Anfänger-Themen 10
T Collections Queue<? extends Number> add() offer() Java Basics - Anfänger-Themen 13
S Klasse extends HashMap Java Basics - Anfänger-Themen 20
L Problem mit Vererbung (extends) cannot find symbol Java Basics - Anfänger-Themen 3
D MyActionListener extends Thread Java Basics - Anfänger-Themen 3
H2SO3- Designfragen (mehrfach extends) Java Basics - Anfänger-Themen 11
G Unterschied e extends y vs ? extends y Java Basics - Anfänger-Themen 5
X List von Klasse B als List von Klasse A (B extends A) Java Basics - Anfänger-Themen 2
H extends Locale Java Basics - Anfänger-Themen 4
O import ja....extends nein Java Basics - Anfänger-Themen 5
G Muss es immer extends sein ? Java Basics - Anfänger-Themen 9
N class Test<E extends MyAbstractClass> => typ von E? Java Basics - Anfänger-Themen 5
K mehrere Extends Java Basics - Anfänger-Themen 2
S extends Vector<xyz> Java Basics - Anfänger-Themen 10
S new .() extends JDialog {.} Java Basics - Anfänger-Themen 15
S extends und Konstruktor Java Basics - Anfänger-Themen 8
E Interface extends Observable Java Basics - Anfänger-Themen 13
G Wiedermal vererbung, extends JDialog extends Exception ? Java Basics - Anfänger-Themen 8
U extends JLabel & Thread Java Basics - Anfänger-Themen 2
G Innere klasssen unde "extends" klassen definieren, Java Basics - Anfänger-Themen 2
frau-u JMenu mit extends JPanel? Java Basics - Anfänger-Themen 4
G "extends DBConnection" funktioniert nicht Java Basics - Anfänger-Themen 15
N extends / implements / static, bedeutung ?? Java Basics - Anfänger-Themen 12
C Problem mit Zeichnen auf einer extends Canvas Class... Java Basics - Anfänger-Themen 2
F Wie kann ich diese NullPointerException umgehen?! Java Basics - Anfänger-Themen 41
Elaurin Erste Schritte effektiv lernen mit Java umgehen zu können? Java Basics - Anfänger-Themen 5
D NullPointerException umgehen Java Basics - Anfänger-Themen 17
D Mit mit geschweifter Klammer umgehen Java Basics - Anfänger-Themen 5
T Methoden Java Methode "umgehen" Java Basics - Anfänger-Themen 2
Meeresgott OOP Richtig mit java.util.Property umgehen Java Basics - Anfänger-Themen 22
U Vererbung Mehrfachvererbung - Wie umgehen? Java Basics - Anfänger-Themen 3
L Methoden Methoden umgehen Java Basics - Anfänger-Themen 5
D Compiler-Fehler Wie kann ich das Problem umgehen? Java Basics - Anfänger-Themen 2
P Gleichverteilung umgehen, Werte nacheinader zuweisen? Java Basics - Anfänger-Themen 1
B DTD. umgehen/ignorieren Java Basics - Anfänger-Themen 3
O Main-Methode static modifier umgehen Java Basics - Anfänger-Themen 10
F wie mit einer ioexception umgehen Java Basics - Anfänger-Themen 10
-horn- Wie am Einfachsten mit Config-Datei umgehen. Welches Format? Java Basics - Anfänger-Themen 6
P Online Etests umgehen Java Basics - Anfänger-Themen 29
G Überschreiben einer Variable umgehen Java Basics - Anfänger-Themen 6
F Wie kann ich call by reference umgehen? Java Basics - Anfänger-Themen 14
M oktale Interpretation der führenden Null umgehen Java Basics - Anfänger-Themen 5
S Mit Collection<int[]> umgehen Java Basics - Anfänger-Themen 2
F Wie muss ich mit Preferences umgehen. Java Basics - Anfänger-Themen 5
F Call-By-Reference umgehen Java Basics - Anfänger-Themen 4
T Umgehen eines remote mySQL-Zugriffes? Java Basics - Anfänger-Themen 14
E Reihenfolge der Werte umdrehen (mittels statischem int-Array Java Basics - Anfänger-Themen 3
M Anzahl Kommandozeilenparamter mittels Methode Java Basics - Anfänger-Themen 11
B Race Condition mittels Semaphore verhindern Java Basics - Anfänger-Themen 13
B Dom Manipulationen mittels Java Java Basics - Anfänger-Themen 8
ravenz Schleife mit for über String Array „zahlen“und prüfen ob Wert „a“ oder „b“ oder „c“ entspricht (mittels || ) Java Basics - Anfänger-Themen 4
D Gerade oder ungerade Zahl mittels Methoden Java Basics - Anfänger-Themen 13
Fats Waller Compiler-Fehler Kann ich einen String und die Summe zweier Char Werte mittels der println Anweisung ausgeben Java Basics - Anfänger-Themen 4
P9cman Vokale in einem String überprüfen mittels Rekursion Java Basics - Anfänger-Themen 8
Poppigescorn Arrayliste Mittels Scanner erweitern Java Basics - Anfänger-Themen 6
TimoN11 Quadratwurzel mittels Funktionswert der Quadratfunktion Java Basics - Anfänger-Themen 9
Khaled-Abo Ziffern unterscheiden mittels einer For-Schleife Java Basics - Anfänger-Themen 6
L Quadratwurzelrechnung mittels Heron-Verfahren Java Basics - Anfänger-Themen 6
P Klassenübergreifende Ausgabe mittels "getter" nicht möglich Java Basics - Anfänger-Themen 21
M Objekte mittels equals vergleichen Java Basics - Anfänger-Themen 14
I csv auslesen, mittels List Java Basics - Anfänger-Themen 18
V Erste Schritte Potenzen b^n mittels Schleife ermitteln Java Basics - Anfänger-Themen 7
S XML mittels HTTP Get Anfrage Java Basics - Anfänger-Themen 4
W Teilstring durch Teilstring mittels StringBuilder ersetzen Java Basics - Anfänger-Themen 7
P Liste mit Lücken mittels Filter aggregieren Java Basics - Anfänger-Themen 7
M Methoden Mittelwert rationaler Zahlen mittels Methode Java Basics - Anfänger-Themen 4
P Klassen In einer Autoklasse das Objekt Auto mittels Collection Speichern Java Basics - Anfänger-Themen 4
M Fibonacci rekursiv mittels Cache Java Basics - Anfänger-Themen 17
K Methoden Zahlensysteme umwandeln mittels Rekursion Java Basics - Anfänger-Themen 5
S int-Array mittels Arrays.sort() in einer Schleife sortieren. Java Basics - Anfänger-Themen 2
A JavaScript Object Notation einbinden mittels Maven Java Basics - Anfänger-Themen 7

Ähnliche Java Themen

Neue Themen


Oben