Clanintern Clanintern Clanintern

Forum

Öffentliche Foren
FORUM: Spiele & Computer THEMA: [JAVA] Interface-Problem
AUTOR BEITRAG
Shaker

RANG Godlike

#1 - 02.05 15:47

Hallo liebe CI-Community,

ich habe, wie im Titel schon angekündigt, ein kleines Problem mit einem Java-Interface.

Zum Problem:

Ich habe eine Klasse A. Diese hat die Attribute a und b und die zugehörigen get und set Methoden (public getA, getB, setA, setB).

Weiterhin habe ich eine Klasse B mit dem Attribut a und auch hier public getA und setA.

Diese beiden Klassen implementieren ein Interface I.

Okay jetzt zum Problem. Im Interfache ist steht natürlich die getA und setA Methode, nur was mache ich mit der getB und setB Methode?

Habe mir folgende Überlegungen gemacht:

- die Methoden getB und setB mit in das Interface schreiben, was allerdings zur folge hätte, dass ich sie auch in der Klasse B implementieren müsste und diese dann nur irgendwelche Pseudodaten zurückgeben (find ich recht unschön)

- die Methoden getB und setB mit ins Interface schreiben und als abstract definieren. Okay, hier habe ich nicht mehr das Problem, dass ich sie in der Klasse B implementieren MUSS aber somit verschiebe ich ja das Prüfen, ob es die Methode gibt oder nicht auf die Verantwortlichkeit des Programmierer und das ist glaub ich nicht der Sinn eines Interfaces.

- ansonsten könnte ich auch im Programmcode die variablen vom definitionstyp I dann bei der Instanzerzeugung auf A oder B casten. Allerdings wird das zum einen recht aufwendig und zum anderen kann ich dann auch gleich das Interface weglassen

- als viertes ist mir in den Sinn gekommen, eine zentrale get und set Methode für alle Attribute (welches Attribut wird dann über nen String als Parameter identifiziert. gibt es diesen string nicht, wird ne exception alla, AttributNotFoundException geworfen). Allerdings zerstört diese Variante alles was ich in Sachen Java-Programmierung bisher "gelernt" habe und zudem auch die schöne Fkt. der Source-Code-Generierung durch Eclipse..


So nun die Frage an euch, wie wird das Problem softwaretechnisch richtig gelöst?

Bin für jede Hilfe dankbar
horst

RANG Prophet of Clanintern

#2 - 02.05 17:13

interface A
getA
setA

interface B extends interface A
getB
setB

class A implements interface A
class B implements interface B

...

falls extends da falsch ist, dann war es auch implements. ich verdreh das manchmal.
Shaker

RANG Godlike

#3 - 02.05 17:47

mh, klingt grundlegend recht logisch.. auch wenn man eine vererbung ja an sich nicht benutzen sollte ...

aber ist wahrscheinlich die bis jetzt beste mir bekannte lösung zu dem problem..
horst

RANG Prophet of Clanintern

#4 - 02.05 17:53

"auch wenn man eine vererbung ja an sich nicht benutzen sollte ... " warum nicht?
Shaker

RANG Godlike

#5 - 02.05 18:19

also nen Prof von uns meinte, dass die Vererbung zwar anfänglich DIE Neuerung schlechthin war (in OOP), aber später immer mehr als schlecht empfunden wurde/wird, da niemand mehr überblicken konnte/kann was nun woher kommt und wo implementiert wird usw.

das Argument sehe ich bei einer Vererbung über mehr als 2 klassen auch ein..

und deswegen soll man halt möglichst ganz auf die direkte Vererbung verzichten und es mit Interfaces lösen..


Aber naja, der Prof. meinte auch, dass Kommentare das Deo für Code-Smells sind und somit ein Kommentar ein Anzeichen für schlechten Code ist. Als Abhilfe hierfür hat er gesagt, man solle sich bei Kommentaren die zur Verständnis von Codezeilen dienen, lieber eine Methode mit aussagekräftigen Namen schreiben und dort den Code rein nehmen..

okay, in einem gewissen Sinne kann ich ihm ja recht geben, aber ich finde dass man es auch übertreiben kann..

Ich danke dir zumindest! Hab es jetzt so gelöst und mein Qualitätssicherer meinte auch, dass dies die beste Möglichkeit ist
horst

RANG Prophet of Clanintern

#6 - 02.05 18:23

"toller" Prof. Meiner Meinung nach gibt es da keine absolute Wahrheit. Dokumentation ist was ordentliches. Was bringt's mir, wenn ich nachher in Geschäftslogik 200 Methoden mit tollen Namen habe und die dann auch nicht mehr überblicke. Dann doch lieber eine, mit einem griffigen Namen und ein paar Parametern, die dann gut mit JavaDoc dokumentiert ist. Dann können auch Fremde sofort lesen, worum es da geht, was erwartet wird und was man im Normalfall zurückbekommt und auf welche Exceptions man reagieren kann und oder muss.

Also im Endeffekt: Hör nicht auf den. Kannst natürlich auch 2 Interfaces und 2 Klassen machen und den Code kopieren.. Dadurch wird er ja "SUPER" wartbar. Natürlich muss man nicht zwingend alles mit jedem verheiraten und vererben... Aber zu sagen, dass Vererbung prinzipiell was schlechtes ist.. naja ... soll er halt wieder schön zur funktionalen Programmierung gehen...
vaest´ark // patrick *ich bin hier nicht der depp*

RANG Master of Clanintern

#7 - 02.05 18:43

also ich hab mich letztens noch gefreut, das es vererbung gibt. sonst hätte ich jetzt in 5 oder 6 verschiedenen klassen je 5 methoden mit exakt dem selben code und exakt der selben aufgabe.
da hab ich dann einfach eine basisklasse (als abstrakte) gebaut und die einfach implementiert. das hat mir ungefähr 1000 zeilen code gespart. naja.

zu den kommentaren: ich bin ja selbst eher einer der kommentare wie
// schleife optimieren
// aufräumen
// TODO: bug bei $fehler fixen
hinterlässt, aber kommentare verteufeln? niemals die haben mir sogar in eigenem code schon mehrfach den hintern gerettet
horst

RANG Prophet of Clanintern

#8 - 02.05 18:52

rischdisch... oop ist cool un kommentare rocken. dein qm wird es dir später danken
NeDoH-*mit Wii*

RANG Deckschrubber

#9 - 02.05 20:40

Naja die Kernaussage zu Vererbung war wohl eher ne andere:
ist schon ne tolle Sache, wird aber oft übertrieben und führt dann zu Problemen. Letztendlich soll guter Code die eigentliche Komplexität des Problemes zähmen. Vererbung kann das Gegenteil bewirken, gerade wenns mal über mehr als 5 Hierarchien geht und Funktionen häufig überschrieben oder gar ausgeblendet werden oder solche Scherze.

Ich hab das damals in "Code Complete" gelesen und das klang schon recht einleuchtend.

Also wenn man weiß was man tut und es noch übersichtlich ist, dann vereinfacht Vererbung ne Menge. Aber wenn mans übertreibt gehts ziemlich nach hinten los.

Ähnlich bei Kommentaren, da gabs auch immer wieder Trends:
irgendwann kam mal auf man soll jede Zeile Code kommentieren, damit man wirklich versteht was passiert und jeden Schritt begründet. Ist natürlich quatsch, guter Code braucht das nicht in jeder Zeit, gutem Code sieht man an was er macht. Aber eben auch nicht immer, Klartext hilft halt doch noch enorm schneller reinzukommen, gerade neuen Leuten. Und für größere Zusammenhänge braucht man einfach Kommentare, geht ja nicht nur darum WAS passiert sondern auch WARUM.

Aber ich denke der Prof hat das schon auch so gemeint.
horst

RANG Prophet of Clanintern

#10 - 03.05 07:54

Hoffen wir es mal. Gegen übertriebene Hierarchien und Kommentare zu jeder Zeile habe ich auch was Allerdings sollte schon eine wohldefinierte API ausführlich dokumentiert werden. Und gerade für das angesprochene Problem erscheint mir Vererbung doch recht nützlich.
Shaker

RANG Godlike

#11 - 03.05 15:58

Holla, hier ist ja einiges passiert

Auf alle Fälle ist die Vererbung für das Problem sehr nützlich.

Zum Thema Prof.: Naja er ist halt so nen Typ der immer alles perfekt haben will usw. Klar hat er in einem gewissen Maße recht, aber solange man es mit Kommentaren und der Vererbung, wie schon oft gesagt, nicht übertreibt, dann geht das glaube ich in Ordnung...
Morath

RANG Deckschrubber

#12 - 07.05 09:13

Ich möchte mal nochmal kurz auf das ursprüngliche Problem eingehen:

Ein Basisinterface A mit getA/setA zu erweitern auf ein neues Interface B mit zusätzlichen setB/getB (horsts Vorschlag aus #2) mag als sinnvolle Lösung erscheinen. Es führt aber zu genau dem gleichen Problem, dass es Stellen im Programmablauf geben kann, an denen man unbedingt eine Instanz von B braucht, diese aber nicht sofort erkennt, wenn man mit Variablen vom Typ A arbeitet.

Der Sinn des Interfaces ist es ja, etwas in der folgenden Art zu ermöglichen:

code:

A[] objects = new A[] { new ClassA(); new ClassB() };

for (int i = 0; i < objects.length; i++) {
  objects[i].setA(i);
}


Wenn ich jetzt aber ne Stelle hab, an der ich unbedingt auf getB/setB zugreifen muss, dann bleibt mir da gar nichts anderes übrig, als eine instanceof-Prüfung vorzunehmen:

code:

if (objects[i] instanceof B) {
  ((B) objects[i]).setB(0);
}


Ich gewinne durch die Verwendung von zwei Interfaces erstmal überhaupt nichts. Jetzt gilt es aber das konkrete Problem anzusehen: Unterscheidet sich die Implementierung der getA/setA-Methoden in den Klassen A und B?

Falls nein reicht ja eine einfache Vererbung, in der Klasse A getA/setA implementiert und Klasse B einfach Klasse A erweitert und zusätzlich getB/setB implementiert:

code:

public class A {
  public void setA(...) {
    ...
  }
  public ... getA() {
    ...
  }
}

public class B extends A {
  public void setB(...) {
    ...
  }
  public ... getB() {
    ...
  }
}


Falls tatsächlich eine unterschiedliche Implementierung von getA/setA notwendig ist, reicht es normalerweise aus, genau diese Methoden in ein Interface zu packen, das dann beide Klassen implementieren und Klasse B bietet zusätzlich getB/setB an:

code:

public interface A {
  void setA(...);
  ... getA();
}

public class AImpl implements A {
}

public class B extends A {
  public void setB(...) {
    ...
  }
  public ... getB() {
    ...
  }
}


Das wäre meiner Meinung nach die "klassische" Alternative zu horsts Vorschlag, den ich aber auch keinesfalls schlecht finde!
Im Gegenteil gefallen mir in komplexeren Datenmodellen solche Lösungen mit published interfaces sogar besser als das was ich jetzt grade geschrieben hab. Allerdings ist das eben immer von der konkreten Problemstellung abhängig. Im gegebenen, scheinbar sehr einfachen Fall hätte ich wahrscheinlich nicht den Aufwand betrieben, gleich zwei voneinander erbende interfaces einzuführen, nur um dann jeweils eine Klasse zu haben, die jeweils eines davon implementieren. So ein Konzept ist sinnvoll für komplexere Klassen, die intern mehr voneinander wissen wollen als sie an andere packages exportieren wollen (das angesprochene Konzept der published interfaces).


Zum Thema Vererbung kann ich noch sagen, dass sie in vernünftigem Maß einfach nötig ist, um Codeduplikate zu vermeiden, die irgendwann einfach nicht mehr wartbar werden.
Kommentare im code sind an den Stellen nötig, an denen nicht sofort ersichtlich ist, wieso bestimmte Sachen gemacht werden. Jede Zeile zu kommentieren ist extrem unsinnig, genauso wie kleine Codestückchen zum z.B. Daten umkopieren oder irgendwelche Prüfungen auf null-Referenzen - Gültigkeitsbereiche für Parameter und zu erwartende Exceptions müssen ja schon in der API-Doku gut dokumentiert sein.
Shaker

RANG Godlike

#13 - 07.05 11:48

Danke für deinen Beitrag. Ist auch ne interessante Variante, allerdings ist für mein Problem die obere Variante besser geeignet.

Das Problem ist auch um einiges komplexer als oben dargestellt. Wollte es allerdings aufgrund des Verständnisses usw. nur auf das eigentliche Problem abstrahieren.