HI!
Ich schaue mir gerade sehr viele Beispiele zur Programmierung von GUIs an. Einige nutzen einfach bestehende Funktionen, die anderen nutzen "extends" und "implements". Allerdings ist mir der wirkliche unterscheid noch nicht ganz bewusst?
Spare ich schreibarebitem, wenn ich eine bestehende Funktion erweitere?
Was sind die Vorraussetzungen: muss im beim "extenden" mehr ueber den Aufbau einer Klasse wissen?
Gibt es spezielle Dinge auf die ich aufpassen muss, wenn ich die eine oder andere Programmierweise verwende?
Wann nutze ich "extends" und fuer was nehme ich "implements"?
Mit dem Schlüsselwort "extends" wird eine bestehende Klasse erweitert, mit dem Schlüsselwort "implements" wird ein "Interface" (=Schnittstelle, besondere Form einer Klasse) implementiert.
ich glaube das hier zu erklären würde zu weit führen, ich würde vorschlagen, dir einfach mal die javainsel durchzulesen, bzw die grundlagen der OOP in java zu studieren.
nur kurz zum thema:
ich glaube auch, du vertust dich mit den begriffen "funktionen" und "klassen". klassen sind mit extends erweiterbar, interfaces lassen sich mit implements einbinden. ich würde sagen, lesen, lesen und lesen!
Bei den beiden Dingen geht es um Vererbung. Das wort extends wird verwendet um von einer Klasse abzuleiten (wenn man genau vom Englischen übersetzt: eine Klasse erweitern). Das Wort implements wird verwendent, um Interfaces zu implementieren.
Ich kann dir jetzt leider nicht alles über Vererbung erklären, da müsste ich wohl mehrere Seiten Text schreiben. Falls du ein Buch hast suche da mal nach "Vererbung". Falls du noch nicht weisst was genau Klassen und Objekte sind müsstest du das unbedingt auch noch nachlesen.
Falls du kein Buch hast... hier kannste alles nachlesen: Click me
"nur 3 gleiche Antworten". Ich war auch schon am Schreiben, hab aber zum Glück vorher nochmal nachgeschaut. Schließe mich meinen Vorrednern voll und ganz an!
Hehe, darauf habe ich gar nicht geachtet. Thx für den Hinweis. Ich habe die Tutorials nicht so oft gelesen und kenne das Buch auch nicht. Hatte deswegen auch keine Ahnung bei welcher Auflage die sind. ^^
Weniger schreibarebit wenn man einen eigenen Typ mehrfach nutzen will,... (wobei ich dann auch direkt eine eigene Klasse dafuer schreiben koennte, die nicht erbt, sondern nur von der anderen Klasse "nutzt")? Oder ist das einfach komplett egal. Gibt es keine bevorzugte Weise wie man etwas programmieren sollte?
Die Java-Insel fuer eine Antwort darauf zu lesen waere wahrscheinlich etwas uebertrieben.
Dass man implements fuer das einbinden von Interfaces verwendet hilft auf jedenfall weiter. Kann ich dann aich mherere Interfaces einbinden? (naja, dafuer fehlt mir das wissen darueber, was in interface ist, aber ich werde es nachlesen.)
Die Java-Insel fuer eine Antwort darauf zu lesen waere wahrscheinlich etwas uebertrieben.
Dass man implements fuer das einbinden von Interfaces verwendet hilft auf jedenfall weiter. Kann ich dann aich mherere Interfaces einbinden? (naja, dafuer fehlt mir das wissen darueber, was in interface ist, aber ich werde es nachlesen.)
Weniger schreibarebit wenn man einen eigenen Typ mehrfach nutzen will,... (wobei ich dann auch direkt eine eigene Klasse dafuer schreiben koennte, die nicht erbt, sondern nur von der anderen Klasse "nutzt")? Oder ist das einfach komplett egal. Gibt es keine bevorzugte Weise wie man etwas programmieren sollte?
das problem ist, wenn du noch keinerlei Ahnung von Vererbung hast helfen natuerlich auch nicht viel Schlagworte, da die dir noch weniger sagen werden.
zb. "Weniger schreibarebit wenn man einen eigenen Typ mehrfach nutzen will" hat mit beiden Konzepten nix zu tun.
um dir aberi Schlagworte zu liefern:
Vererbung (extend) sollte so oft wie moeglich vermieden werden und Delegation (Klasse nutzt Funktionalitaet der anderen, erbt sie aber nicht) bevorzugt werden.
Dass man implements fuer das einbinden von Interfaces verwendet hilft auf jedenfall weiter. Kann ich dann aich mherere Interfaces einbinden? (naja, dafuer fehlt mir das wissen darueber, was in interface ist, aber ich werde es nachlesen.)
Das kann man so direkt nicht beantworten. Es ist halt abhängig davon, was Du machen möchtest. In einem Fall ist das Erben einer Klasse sinnvoll, in einem anderen Fall halt das Implementieren eines Interface. Generell kann man sagen: bei Spezialisierung vererbe ich (Bsp.: Auto erbt von KFZ, ergänzt es um vier Räder, Motorrad erbt auch von KFZ, ergänzt es aber nur um zwei Räder). Wenn ich bestimmte Funktionen zur Verfügung stellen möchte, die nicht unbedingt was mit der Primärfunktion der Klasse zu tun haben, dann implementiere ich das als Interface (Aschenbecher leeren macht im Auto und LKW Sinn, aber nicht im Motorrad...andererseits könnte es auch im Wohnzimmer oder in der Kneipe nutzen, die mit einem KFZ nichts gemein haben).
Die Java-Insel fuer eine Antwort darauf zu lesen waere wahrscheinlich etwas uebertrieben.
Wenn ich bestimmte Funktionen zur Verfügung stellen möchte, die nicht unbedingt was mit der Primärfunktion der Klasse zu tun haben, dann implementiere ich das als Interface (Aschenbecher leeren macht im Auto und LKW Sinn, aber nicht im Motorrad...andererseits könnte es auch im Wohnzimmer oder in der Kneipe nutzen, die mit einem KFZ nichts gemein haben).
Sry wenn ich den Thread hier mal für meine eigene Frage missbrauche. Wenn du so ein Interface dann benutzt wie geschieht das? Interfaces enthalten doch keine Methoden. Aschenbecher leeren ist ja ne Aktion und wird also irgendwie als Methode umgesetzt werden. Du müsstest ja dann die eigentlich Methode in jeder Klasse implementieren (also tatsächliche schreiben) die das Interface implementiert. Führt das nicht zu doppeltem Code?
EDIT: noch mal kurz um meinen Punkt etwas klarer zu machen ...
Java:
// interfacepublicinterfaceAschenbecherLeerable{publicvoidleereAschenbecher();// hier leider keine direkte Implementierung möglich}// eine klassepublicclassRaucherautoimplementsAschenbecherLeerable{publicvoidleereAschenbecher(){System.out.println("Aschenbecher wird geleert.");System.out.println("Auto ist wieder sauber.");}}// zweite klassepublicclassKneipeimplementsAschenbecherLeerable{publicvoidleereAschenbecher(){// doppelter code? ist das wirklich gut?System.out.println("Aschenbecher wird geleert.");System.out.println("Kneipe ist wieder sauber.");}}
Hier geht es darum, Schnittstellen zur Verfügung zu stellen, und nicht um Codeduplikate zu vermeiden. Allgemein geht es in der OOP nicht darum, möglichst wenig Code zu schreiben.
aber wie faetz schon sagte - interfaces definiern reine schnittstellen, unabhaengig wie die Implementierung ist.
bestes bsp ist sortierung und Comparable... einem Sortieralgorithmus kann und soll es ziemlich egal sein was fuer Objekte er sortiert (Auto, Mensch, Integer, Meer, Bier) und vor allem wie er es sortiert (aufsteigend, absteigend, willkuerlich)... er allein basiert darauf, dass die Objekte die er bekommt sortierbar sind (in java z.b. ueber das Interface Comparable) - wie aber ist sache der Objekte selber.
Weitere Problematiken ... wenn ich in einer der Klassen nun irgendwann das Verhalten also die Implementierung der durch das Interface bereitgestellte Methode verändern möchte, so muß ich das an den Klassen direkt tun. Und das eventuell sogar in mehreren Klassen. Klingt im Sinne von OOP nicht besonders elegant. Und hört sich sehr fehlerträchtig an, da doppelter Code usw.
Weitere Problematiken ... wenn ich in einer der Klassen nun irgendwann das Verhalten also die Implementierung der durch das Interface bereitgestellte Methode verändern möchte, so muß ich das an den Klassen direkt tun. Und das eventuell sogar in mehreren Klassen. Klingt im Sinne von OOP nicht besonders elegant. Und hört sich sehr fehlerträchtig an, da doppelter Code usw.
wenn sich die Implementierung einer Klasse aendert MUSST du natuerlich die Klasse aendern... das interface selber oder alle anderen Implementierungen des interfaces bleiben komplett unberuehrt davon.
Nochmal das sortierbeispiel... wenn du nun entschlossen hast dass Biere nicht nach Alkoholgehalt sondern nach Helligkeit, aenderst du 1 Klasse, naemlich Bier... das interface und alle Menschen, Meere, Integer, Personen oder was auch immer, die ebenso sortierbar sind bleiben so wie sie sind....
nochmals - INTERFACES produzieren KEINEN doppelten code per se!
aenderst du natuerlich das Interface selber, so muessen auch alle implementierenden Klassen geaendert werden
Aber verschiedene Klassen machen bei einer Methode aus einem Interface auch oftmals verschiedene Dinge. Wenn eine Methode für viele Klassen gleich sein muss, dann packt man die halt in eine Superklasse.
Weitere Problematiken ... wenn ich in einer der Klassen nun irgendwann das Verhalten also die Implementierung der durch das Interface bereitgestellte Methode verändern möchte, so muß ich das an den Klassen direkt tun. Und das eventuell sogar in mehreren Klassen. Klingt im Sinne von OOP nicht besonders elegant. Und hört sich sehr fehlerträchtig an, da doppelter Code usw.
Wieso weitere "Problematiken", hab schon die erste Problematik nicht gesehen...
Einmal kann man abstrakte Klassen schrieben die das Interface implementieren und so gemeinsamkeiten bzw. redundanten Code einsparen, und dann gibt es ja noch das mittel der Delegation.
Man muss es halt auch richtig einsetzen, dann ist es "auch im Sinne der OOP elegant", was auch immer das heisst
Hmmm, das Beispiel zeigt deutlich in deine Richtung, da Sortierbarkeit etwas sehr spezielles ist. Mir geht es aber darum wenn zwei Klassen die Methode größtenteils sehr ähnlich implementieren.
Nehmen wir mal das Beispiel von oben mit dem Aschenbecher. Ich will dass beide Klassen nur "Aschenbecher wird geleert." anzeigen. Dann muss ich in beiden Klassen den genau identischen Code schreiben. Was habe ich nun gewonnen durch das Interface? Oder ist ein Interface hier sogar die falsche Lösung?
wie schon von anderen netten Forenmitgliedern erwaehnt... bei gleichheit in der Spezialisierung sollte man eher an Vererbung denken.
Interfaces dienen - wie gesagt - nur dafuer eine schnittstelle zu bieten, gemeinsame Funktionalitaet bereitzustellen... sobald man auch wirklich gleiches Verhalten hat kann ein Interface auch falsch sein.
Auf das Beispiel übertragen: Wenn es beim Leeren des Aschenbechers mehr zu tun gäbe, als eine Zeile auszugeben, würde es ggf. eine Klasse "Aschenbecher" geben, die die (kompliziere, lange*) Methode "leere" anbietet - und die Implementierungen von AschebäschäLeerable hätten dann jeweils ein Aschenbecher-Objekt, und in der leereAschenbeacher-methode würde dann jeweils nur "this.aschenbecher.leere()" aufgerufen.
Das mit der Superklasse... hier mal ein Beispiel wo ich mir das nicht vorstellen kann, wie es funktionieren soll: wir betrachten Autos mit Aschenbechern.
Java:
// superklasse Apublicclass PKW {// hier sind wichtige sachen für pkws}// superklasse Bpublicclass LKW {// hier sind wichtige sachen für lkws}// klasse einspublicclassCabrioextends PKW {leereAschenbecher(){// hier kommt die implementierung rein// der aschenbecher soll auf die exakte weise Methode A geleert werden
code von MethodeA....}}// klasse zweipublicclassAutoMitDachextends PKW {leereAschenbecher(){// hier kommt die implementierung rein// der aschenbecher soll auf die exakte weise Methode B geleert werden
code von MethodeB....}}// klasse dreipublicclassBrummiextends LKW {leereAschenbecher(){// hier kommt die implementierung rein// der aschenbecher soll auf die exakte weise Methode A geleert werden
code von MethodeA....}}
Was wäre hier der richtige Weg die Methode "leereAschenbecher()" zu implementieren? Cabrio und Brummi tun das exakt identische bei der Methode haben aber zwei verschiedene Superklassen. Cabrio und Käfer implementieren die Methode unterschiedlich. Wie lösen wir das?
Irrelevant wie du das löst, kannst du immer noch ein Interface dafür implementieren, damit die Putzmann-Implementation auch alle Aschenbecher finden und gleich behandeln kann.
eine moegliche loesung ist PKW & LKW von einer Klasse Fahrzeug loesen und dort die funktionalitaet anbieten.
Bevor nun auf alle moeglichen Beispiele und Unsinnsbeispiele eingegangen wird - wenn man code kopien haben will wird man sie auch immer haben und es gibt bestimmt zig bsp bei denen es (minimal) immer kopien geben wird.
Alle nun herbeizuziehen um den generellen Unsinn von Interfaces zu zeigen halt ich fuer unsinnig
Was wäre hier der richtige Weg die Methode "leereAschenbecher()" zu implementieren? Cabrio und Brummi tun das exakt identische bei der Methode haben aber zwei verschiedene Superklassen. Cabrio und Käfer implementieren die Methode unterschiedlich. Wie lösen wir das?
Eine Oberklasse "Fahrzeug mit Aschenbecher" die erstmal eine generelle Methode gibt den Aschenbecher zu leeren (einfach aus dem Fenster rausschmeissen...).
Wenn jetzt doch irgendwie anders geleert wird (an der Tanke irgendwo auskippen) dann kann das ja immer noch geändert werden.
So würd ichs zumindest machen. Denn die Lösung "alles aus dem Fenster werfen" funktioniert bei jedem Fahrzeugtyp (beim Cabrio ist da eben ein imaginäres Fenster).