Vector Generizität

  • Ich habe eine abstrakte Klasse, wo es einen Vector mit der eigenen Klasse gibt:

    Da die Klasse abstrakt ist, wird diese natürlich vererbt und somit verändert sich auch der Typ im Vektor zu der Klasse, die hierbei die Klasse erbt, dh:

    MyNewClass1 erbt von MyClass
    --> brauche --->
    Vector<MyClass> zu Vector<MyNewClass1>

    Hierbei habe ich versucht mit Wildcards zu arbeiten:

    Code
    Vector<? extends MyClass>

    jedoch kann ich mit diesen Wildcards nicht instanzieren. Wie kann ich hierbei mein Problem lösen??

  • Ich glaube dein Problem ist, das Du Vererbung hier falsch einzusetzen versuchst.

    Durch Vererbung drueckt man ja eine "ist-ein" Beziehung aus. Das heisst dass alle Eigenschaften der Superklasse auch auf die Kindklasse zutreffen.

    Wenn Du in deinem Beispiel eine Klasse MyNewClass1 von MyClass erben laesst, dann bedeutet das, dass MyNewClass1 eine List vom Typ MyClass besitzen muss. Nicht nur weil da der Compiler schreit, sondern weil Du sonst keine gueltige Vererbung mehr einsetzt.

    Eine List<MyNewClass1> ist restriktiver als eine List<MyClass>, also nicht vom gleichen Typ. Deshalb wuerde ich eher dazu raten das Design zu ueberdenken, anstatt einen Hack zu suchen, mit dem Du die Vererbung umgehen kannst.

    Vererbung sollte man ganz allgemein so selten wie nur moeglich einsetzen. In den meisten Faellen kann man Beziehungen genauso ueber Delegation ausdruecken. Und Delegation ist viel sicherer und verstaendlicher als Vererbung.

  • Ich denke, ich verstehe sein Problem. Wenn er jetzt in MyNewClass1 Objekte aus seinem Vektor nehmen und damit arbeiten möchte erhält er nur eine Referenz auf MyClass-Objekte und muss sie erst manuell casten. Er kann sich dabei aber nicht mal sicher sein, dass es überhaupt MyNewClass1-Objekte sind.

    Ich hatte genau dieses Problem mal in einer C#-Anwendung und hab keine sinnvolle Lösung gefunden. Mein "Wunsch" wäre ja ein keyword analog zu this, dass man statt dem aktuellen Typ einsetzen kann. (Ich weiß schon, dass es this.getClass() gibt, aber ein Vector<this.getClass()> funktioniert ja verständlicher Weise nicht)

  • Ich denke, ich verstehe sein Problem.

    Sein Problem verstehe ich auch. Was ich meinte ist, dass er nicht versuchen sollte, das Problem technisch zu lösen, sondern indem er sein Design überdenkt.

    Wenn Steff100 eine technische Loesung fuer sein Problem findet, dann ist sein Ergebnis nicht mehr objektorientiert. Eine MyClass ist definiert als etwas, dann einen Vektor besitzt, in den jedes Objekt vom Typ MyClass reinpasst. Und einen solchen Vektor hätte MyNewClass1 nicht mehr. Das bedeutet MyNewClass1 ist kein MyClass, und darf deshalb auch nicht von MyClass erben.

    Java, und die Konstrukte, die hier verwendet werden (Klassen, Instanzvariablen, Typisierung etc), wurden aber für objektorientierte Programmierung designed. Wenn er diese Mechanismen jetzt zu umgehen versucht, dann wird er sich nicht nur mit dem Compiler Probleme kriegen - Sein Code wird auch schwerer zu lesen und von anderen Developern missinterpretiert. Denn jeder Programmierer der sich den Code anschaut wird davon ausgehen, dass jede Instanz von MyNewClass1 auch eine Instanz von MyClass ist.

    lg, Benjamin Ferrari, bookworm.at

    2 Mal editiert, zuletzt von a9bejo (6. Januar 2009 um 11:47)

  • Denn jeder Programmierer der sich den Code anschaut wird davon ausgehen, dass jede Instanz von MyNewClass1 auch eine Instanz von MyClass ist.

    Das ist natürlich auch der Fall. Jede Instanz von MyClass bzw erbenden Klassen enthält auch Referenzen auf weitere MyClass-Objekte.

    Jedoch möchte er MyNewClass1 so einschränken, dass sie nur Referenzen auf Objekte vom Typ MyNewClass1 enthält, die ja wie gefordert von MyClass erben. Das ist keine (unerlaubte) Ausweitung der Vererbung sondern eine (imho gültige, teilweise auch sinnvolle) Einschränkung.

  • Zitat


    Jedoch möchte er MyNewClass1 so einschränken, dass sie nur Referenzen auf Objekte vom Typ MyNewClass1 enthält,

    Diese Einschränkung gibt es aber ja in MyClass selber nicht. Also fehlt der Kindklasse eine Eigenschaft der Mutterklasse.

    Die Klasse MyClass ist definiert als "Eine Klasse die einen Vektor besitzt, in den jede Objektinstanz vom Typ MyClass reinpasst".

    Wenn MyNewClass1 jetzt den Vektor restriktiver macht, dann trifft diese Eigenschaft nicht mehr zu: Es kann nicht mehr jede beliebige Instanz von MyClass in den Vektor, sondern nur noch solche, die auch vom Typ MyNewClass1 sind.

    D.h. das MyNewClass1 keine Instanz von MyClass mehr ist.

  • OK, da muss ich dir recht geben. Ich habe jetzt das Problem vom OP gedanklich mit meinem damaligen vermischt, in dem die Liste nach außen hin nur lesbar war.

    In diesem Fall würde ich den Satz so abändern:
    Die Klasse MyClass ist definiert als "Eine Klasse die einen Vektor besitzt, in dem jede Objektinstanz vom Typ MyClass ist".

    So würde die Definition ja nicht verletzt werden.

  • Das ist natürlich auch der Fall. Jede Instanz von MyClass bzw erbenden Klassen enthält auch Referenzen auf weitere MyClass-Objekte.

    Jedoch möchte er MyNewClass1 so einschränken, dass sie nur Referenzen auf Objekte vom Typ MyNewClass1 enthält, die ja wie gefordert von MyClass erben. Das ist keine (unerlaubte) Ausweitung der Vererbung sondern eine (imho gültige, teilweise auch sinnvolle) Einschränkung.

    Hier muss man sich eigentlich nur fragen, ob das Ersetzbarkeitsprinzip [1, 2] erfüllt ist: Kann eine Instanz von MyNewClass1 überall dort eingesetzt werden, wo eine Instanz von MyClass erwartet wird? Wenn ja, dann ist MyNewClass1 ein Untertyp von MyClass. Die Einschränkung, die du da einführen möchtest, würde MyNewClass1 die Eigenschaft "Untertyp von MyClass" absprechen: MyNewClass1 hätte nicht mehr dieselben Eigenschaften wie MyClass. Du würdest quasi den Untertyp allgemeiner machen, als den Obertyp, und das ist nicht erlaubt.

    Huh, nach zweimal Preview und dem Suchen der korrekten VL-OOP-Folien sehe ich, dass a9bejo wieder schneller war.

    [1] http://www.complang.tuwien.ac.at/franz/objektor…rt/oop07-02.pdf
    [2] http://de.wikipedia.org/wiki/Liskovsch…itutionsprinzip

    Restrain the specimen!

    Einmal editiert, zuletzt von daff (6. Januar 2009 um 12:23)

  • Wie kann ich hierbei mein Problem lösen??


    Kommt darauf an, was genau dein Problem ist. Oberflächlich betrachtet kann man sowas lösen, indem die Oberklasse generisch gemacht wird. In C++ geht das so:


    (Die Namen sind nicht wie bei dir, aber du schaffst das schon :) ) Wenn du von den vererbten Klassen MyClass bzw. MyOtherClass aber weiter vererben willst, bekommst du dieselbe Anomalie. Möglicherweise läßt sie sich auf dieselbe Art umgehen. Im klassischen oberflächlichen Sinn ist das wohl tatsächlich nicht objektorientiert, aber wenn du die Lösung deines Problems so besser modellieren kannst, dann go for it.

    *plantsch*


  • In diesem Fall würde ich den Satz so abändern:
    Die Klasse MyClass ist definiert als "Eine Klasse die einen Vektor besitzt, in dem jede Objektinstanz vom Typ MyClass ist".

    So würde die Definition ja nicht verletzt werden.

    stimmt, und die Umsetzung dieser Definition in Java währe, das auch MyNewClass1 Instanzen einen Vektor vom Typ Vektor<MyClass> enthalten.

  • Kommt darauf an, was genau dein Problem ist. Oberflächlich betrachtet kann man sowas lösen, indem die Oberklasse generisch gemacht wird.

    Find ich besser: Ein anders Design (sinnvoller und auch OOP gerechter). Der Typ des Vektors wird ja jetzt nicht mehr in der Base Klasse festgelegt und dann im Kind geändert: Er wird nachträglich injiziert.

    Ich bin aber immer noch der Meinung, dass man wenn möglich ganz auf Vererbung verzichten sollte.

    lg, Benjamin Ferrari, bookworm.at

    3 Mal editiert, zuletzt von a9bejo (6. Januar 2009 um 13:34)

  • Tja, das hatte ich mir gedacht, dass ich hier wohl die Vererbung falsch verwende. Es ist halt hierbei das Problem, dass ich vom Typ des Vektors Methoden aufrufen möchte, die halt MyClass nicht besitzt und dadurch Probleme bereitet.

    Ich habe nun die Möglichkeit von Plantschkuh! hergenommen und die vererbende Klasse mit einem generischen Parameter versehen. Sieht jetzt folgendermaßen aus:

    Hierbei muss ich leider trotzdem einige Variablen casten, welche nicht überprüft werden, aber grundsätzlich wäre eine Vererbung um ursprünglichen Design nicht vorgesehen gewesen. Diese ergab sich leider in der Entwicklung der zusätzlichen Wünsche des Auftraggebers.

    Für OOP würd ich vermutlich jetzt vielleicht mehr, aber immer noch 100Pkt. fürs Bsp bekommen. ;) Würd mich trotzdem interessieren, was ihr von diesem Konstrukt haltet.

    Ich bin aber immer noch der Meinung, dass man wenn möglich ganz auf Vererbung verzichten sollte.

    Das würde halt einen Zusatz von mehreren 100 Zeilen Code pro Klasse bedeutet, der 2 bis mehrmals kopiert werden müsste. Genau das wollte ich damit verhindern.

    2 Mal editiert, zuletzt von Steff100 (6. Januar 2009 um 20:24)

Jetzt mitmachen!

Sie haben noch kein Benutzerkonto auf unserer Seite? Registrieren Sie sich kostenlos und nehmen Sie an unserer Community teil!