Interface - abstrakte Klasse

propra

Aktives Mitglied
Hallo zusammen,

der Titel sollte mein Problem eigentlich schon ganz gut umschreiben.
Mich interessiert, ob es dafür eine pauschale Aussage gibt oder ob man das von Fall zu Fall betrachten muss.
In meinem Programm habe ich ein Interface Symbole und 2 Klassen Rechteck bzw. Kreis, die das Interface implementieren. Jetzt stelle ich aber fest, dass einige der Methoden von der Implementation her identisch sind. Was sicherlich daran liegt, dass ich eine ArrayList mit Symbolen verwalte, wo ich dann aber Elemente vom Subtyp einfüge. Wenn ich nun auf den Elementen der ArrayList eine Methode aufrufe, z.B. zeichneSymbol() wird die entsprechende Methode des Subtyps aufgerufen. Ich glaube der richtige Begriff dafür ist dynamisches Binden.
Jetzt gibt es aber Methoden, wie z.B. istSymbolAusgewaehlt(), die einfach nur einen boolean-Wert abfragen, was bei beiden Symbolen ja gleich ist. Um nun doppelten Code zu vermeiden, würde es doch reichen, die Methode in Symbol zu implementieren. Dann müsste ich das Interface aber zu einer abstrakten Klasse umwandeln.
Daher meine Frage, woran man das festmacht, ob man nun eine abstrakte Klasse nutzen sollte oder ein Interface.

Vielen Dank
 
Zuletzt bearbeitet von einem Moderator:
Ich würd in deinem Fall so ne Struktur aufbauen:
Java:
interface Symbol{
  // Methoden
}

Java:
abstract class AbstractSymbol implements {
  // Methoden implementieren die sich alle teilen
}

Java:
class Symbol1 extends AbstractSymbol {
  // restliche Methoden implementieren
}
 
Zuletzt bearbeitet von einem Moderator:
Hab oben noch nen
Code:
abstract
reineditiert.

Bei der Struktur hast du die Vorteile der Interfaces, und kannst in der abstrakten Klasse den Code reinschreiben den sich alle Unterklassen teilen.
 
Ok, das ist schon mal praktisch.

Sofern es dafür überhaupt eine Antwort gibt, würde mich die Antwort auf die Frage:

Trotzdem noch interessieren. Kann da jemand etwas zu sagen?

Ich arbeite grade ein JavaTutorial durch. Es wurde nichts direkt dazu gesagt, aber ich stelle doch fest:

Für Oberbegriffe/Oberklassen nimmt man class (Auto, Oberbegriff Fahrzeug wird zur Klasse).
Wenn dein Auto aber jetzt etwas können soll (Möglichkeit zum Tunen -> Tunable wird zum Interface).

Ob das immer so ist weiß ich nicht.
 
programmtechnisch ist es egal, ob der gemeinsame Typ verschiedener Klassen ein Interface, eine abstrakte Oberklasse oder auch eine normale Oberklasse ist,
solange es keine offensichtlichen Gründe gibt, kann man das also beliebig machen

Gründe die offensichtliche Gründe werden können sind:
- wenn Methoden fehlen muss man wohl eine abstrakte statt eine vollständige Oberklasse bauen
- bei nur Einfachverbungen und dennoch gewünschten mehreren Schnittstellen geht es ohne Interface nicht
 
Ich danke Dir.
Das hatte ich soweit verstanden, dass Interfaces Eigenschaften von Objekten definieren.
Mir geht es mehr um den Unterschied Abstrakte Klasse und Interface. Ob es dafür irgendwelche Richtlinien gibt.
 
Mir geht es mehr um den Unterschied Abstrakte Klasse und Interface
Sobald du Code hast, kann es kein Interface mehr sein und du nimmst eine abstrakte Klasse.

Letzlich hängt die Entscheidung von Faktoren wie der Größe des Codes, Anzahl der Methoden etc. ab.
 
Zuletzt bearbeitet:
Der Vorschlag von EikeB, Interface und abstrakte Klasse zu nutzen, ist sicherlich die flexibelste Lösung. Allerdings auch die aufwendigste Lösung.

Persönlich verwende ich wann immer möglich EikeBs Vorschlag, und im Zweifellsfalle tendiere ich zum Interface - da bleiben alle Optionen offen. Mit einer abstrakten Klasse schränkt man sich stärker ein.
 
Zuletzt bearbeitet von einem Moderator:
abstrakte Klasse oder Interface ist oft auch eine Geschmacksache. Ein Interface ist flexibler bedeutet aber evtl. Mehraufwand bei der Implementierung. Wenn ein bestimmtes Standardverhalten vorgegeben werden soll reicht ein Interface nicht mehr aus und man benötigt eine abstrakte Klasse. Dies bedeutet allerdings eine Einschränkung in den Vererbungsmöglichkeiten.
Grundsätzlich würde ich sagen definiert eine abstrakte Klasse von welcher "Art" etwas ist, z.B. ein Symbol. Ein Interface definiert eher was mit dem implementierenden Objekt gemacht werden soll, z.B. Paintable/Drawable.
Daher könnte man theoretisch auch eine abstakte Klasse Symbol mit den grundlegenden Eigenschaften eines Symbols definieren und zusätzlich ein Interface Drawable welches die Methode zeichneSymbol vorschreibt.
Einfacher und pragmatischer wäre es hier alles in einer abstrakte Klasse zu definieren und Methoden teilweise zu implementieren.

Da ich persönlich lieber mit Interfaces arbeite, würde ich mich aber in dem Fall auch Fragen, muss/darf ein Symbol wissen, ob es ausgewählt ist. Oder ist es evtl. besser ein separates Model zu implementieren welches die Selektion verwaltet, wie es z.B. viele Swing Komponenten machen (siehe ListSelectionModel)
 
Abstrakte Klassen sollte so weit möglich nur auf einer Package-Ebene nutzbar sein.
Interfaces sollten die Schnittstelle nach aussen bilden.

Grobes Beispiel:
Du hast ein GUI-Projekt, dieses Projekt nutzt eine Bibliothek. Diese Bibliothek unterteilt man in größeren Projekten in zwei Java-Projekte auf. Einmal in das Projekt "mein-projekt-api" und in "mein-projekt-impl".
Das "mein-projekt-api" beinhaltet sämtliche Interface die in deine GUI Projekt öffentlich genutzt werden.
Das "mein-projekt-impl" beinhaltet sämtliche Klassen die die Interface implementieren.

Code Beipiel:

mein-projekt-api mit Package "org.businss.logic":
- Interface "IPersonBusinessLogic" mit "erstellePerson".
- Klasse "PersonBusinessLogicFactory" mit der Methode getPersonInstance. In dieser Methode gibt man dann eine neue Instanz der zu verwendenden "*PersonBusinessLogic" -Klasse zurück.
Du brauchst jetzt in deinem GUI Projekt nirgends einen direkten Verweiss, bzw. eine Instanz bilden über den "mein-projekt-impl". Somit ist das Projekt "mein-projekt-impl" jederzeit unabhängig und kann weggelassen oder ausgetauscht werden.

mein-projekt-impl mit Package "org.business.logic":
- Abstract default (private) Klasse "AbstractPersonBusinessLogic" mit Methode "erstellePerson" die von Interface aus dem Api-Projekt vorgegeben wird..
- Klasse "LehrerBusinessLogic" die, die Methode der "erstellePerson" aus der abstrakten Klasse "AbstractPersonBusinessLogic" überschreibt.

Sinn und Zweck dieser Art ist das man in großen Projekten nicht immer die gesamten implementierten Bibliotheken austauscht, sondern nur die Projekte mit der Implementierung der Businesslogik. Hier in dem Beispiel das Projekt "mein-projekt-impl". Zweiter Vorteil ist das diese Art von Umsetzung sich besser Testen lässt.

Es ist zwar jeden selbst überlassen was er mehr mag, aber grundsätzlich sollte man sich an diese Art richten. Gute Beispiele hierfür sind "Webservice-Projekt" bzw. Implementierung wie JAX-WS usw.
 
Ingesamt sollte man Abstrakte Klassen mit Bedacht einsetzen. Standardmäßig sind erstmal alles Interfaces. Die Abstrakten Klassen können dann an manchen Stellen zwischen dem Interface und der konkreten Implementierung liegen. Aber wie knoppers schon sagte sollte man im allgemeinen dann aufpassen, dass diese Klassen nicht nach außen sichtbar sind. Das Problem dabei wäre, dass Leute ggf. unerwünschterweise davon erben könnten, oder sich an manchen Stellen darauf verlassen, dass "ja sowieso jedes 'IThing' auch ein 'AbstractThing' ist". Besonders kritisch ist es, wenn die abstrakte Klasse irgendwelche "praktischen" public/protected Methoden hat, die NICHT Teil des interfaces sind. Dann sollte man sich genau überlegen, ob und wenn ja welchen Zugriff man da erlauben will. Wenn die Abstrakte Klasse wirklich NUR ein Teil-Implementierung von Methoden aus dem Interface ist, und sonst NICHTS öffentlich anbietet (oder ganz gezielt für die Erweiterung gedacht ist) kann das OK sein. Es gibt aber auch Leute, die propagieren, KEINE abstrakten Klassen einzusetzen (nicht "irgendwelche" Leute, sondern Jaroslav Tulach, der Gründer der NetBeans-Plattform). An manchen Stellen kann das dann IMHO schon aufwändig werden, aber ist natürlich schöner in bezug auf die Klare Trennung zwischen Schnittstelle und Implementierung.

Hm. Ein klares Statement war das jetzt nicht gerade 😳
 
Vielen Dank für die vielen Antworten.

Also scheint es keine ganz einfache Sache zu sein, die ich hier angesprochen habe. Für mein kleines Projekt habe ich es jetzt so gehandhabt, dass ich ein abstrakte Klasse AbstractSymbol habe. Davon erben dann die Klassen Kreis und Rechteck. Diese implementieren dann die Interfaces Clickable, Drawable, Movable und Selectable.
 
eine ganz scheue Bitte:

Könnte wer das Subjekt ändern? Wir verweisen ja des öfteren auf die Forumssuche und die klappt natürlich nur, wenn da "abstrakte" und nicht "abstarkte" steht - Danke.
 
eine ganz scheue Bitte:

Könnte wer das Subjekt ändern? Wir verweisen ja des öfteren auf die Forumssuche und die klappt natürlich nur, wenn da "abstrakte" und nicht "abstarkte" steht - Danke.

Sorry, war mir gar nicht aufgefallen.

Also scheint es keine ganz einfache Sache zu sein, die ich hier angesprochen habe. Für mein kleines Projekt habe ich es jetzt so gehandhabt, dass ich ein abstrakte Klasse AbstractSymbol habe. Davon erben dann die Klassen Kreis und Rechteck. Diese implementieren dann die Interfaces Clickable, Drawable, Movable und Selectable.

Ich glaube das ist doch keine so gute Idee bzw. ergibt sich dadurch ein neues Problem.
Das Interface Symbol wird von der abstrakten Klasse AbstractSymbol implementiert. Die Klassen Kreis und Recheck erben von AbstractSymbol und implementieren die 4 Interfaces Clickable, Drawable, Movable und Selectable. Soweit so gut. Jetzt habe ich eine ArrayList<Symbol>, die alle meine Elemente beinhaltet. Möchte ich nun eine Methode der Interfaces Clickable, Drawable, Movable und Selectable auf einem der Elemente aufrufen, sind diesem die Methoden der Interfaces natürlich nicht bekannt, da das Interface diese Methoden nicht vorgibt.
Jetzt müsste ich überall mit
Code:
if(symbol instanceof Kreis) {}
bzw.
Code:
if(symbol instanceof Rechteck){}
arbeiten. Geht das nicht auch irgendwie anders/einfacher?
Bin für jeden Hinweis dankbar.
 
Nach ein wenig Recherche habe ich herausgefunden, dass Interfaces andere Interfaces durch extends anstatt implements "realisieren" können.
Das hat mich zu folgender Struktur gebracht.

Java:
public interface Symbol extends Clickable, Drawable, Movable, Selectable {

}

abstract class AbstractSymbol implements Symbol {

}

public class Kreis extends AbstractSymbol {

}

Im Moment funktioniert es so, wie es soll. Mich würde jetzt interessieren, ob etwas dagegen spricht es so zu machen.
 
Ist denn wirklich jedes Symbol Clickable, Drawable, Movable und Selectable? Damit schränkst du dich ja gleich wieder ein. Besser wäre es wohl, wenn zumindest einige der Interfaces erst von AbstractSymbol, oder sogar erst von weiteren Unterklassen implementiert werden. Da könnte es z.B. das AbstractClickableSymbol geben...

Wenn du z.B. Methoden von Clickable brauchst, dann musst du im Code nicht
Code:
if( symbol instanceof Kreis ){}
schreiben, sondern
Code:
if( symbol instanceof Clickable ){}
.
 
Vielen Dank Beni.

Im Moment ist es so, dass jedes Symbol auch Clickable, Drawable, Moveable und Selectable ist. Weiß nicht, ob sich das mal ändern wird.
Das die Interfaces erst später implementiert werden, hatte ich ja (siehe meinen Post von 15:30 Uhr). Daraufhin habe ich ja die "Probleme" bekommen, dass ich nun nicht mehr auf einem Element vom Typ Symbol Methoden aus dem z.B. Selectable-Interface aufrufen kann.
Die Lösung könnte vielleicht mit deinem Vorschlag, auf Selectable zu prüfen, realisiert werden. Mir war nämlich gar nicht so 100 %-ig bewusst, dass es jetzt natürlich auch den Typen Selectable gibt und die Elemente von Kreis und Rechteck dann dazu gehören.
Nächste Frage wäre nun, was besserer Stil ist. Vielleicht liegt es an meiner wenigen Erfahrung, aber ich hatte mal gelesen, dass man
Code:
instanceof
nach Möglichkeit vermeiden sollte.
Auch hier wäre ich für weitere Hinweise dankbar.
 

Zurück
Oben