Diskussion:Kreis-Ellipse-Problem
überschreiben/überladen?
[Quelltext bearbeiten]In Python könnte man doch auch Kreis von Ellipse erben lassen und die unnötigen Methoden mit Exceptions überschreiben bzw. überladen, dann wäre das Problem auch gelöst. --Amogorkon 04:17, 1. Dez. 2009 (CET)
- Das geht wohl so gut wie in jeder Sprache. Vermutlich wird das in der Praxis auch meist in vergleichbaren Fällen so gemacht. Toll ist es natürlich nicht, sich hier einen potentiellen Laufzeitfehler einzuhandeln, aber vor allem verstößt es gegen das Liskovsche Substitutionsprinzip (schau Dir das vielleicht mal an) und hier wird das ganze primär aus der theoretischen Sicht betrachtet.--Cactus26 08:12, 1. Dez. 2009 (CET)
Das Rechteck ist ein Quadrat...
[Quelltext bearbeiten]Naja nach der klassischen definition von 'quadrat' und 'rechteck' ist das natürlich schwachfug. aber wenn mann das ganze über einen neuen weg definiert, stellt es sich schon als konsitent heraus, die vererbungsrichtung umzukehren. Sich da zu sperren, nur weil jemand das nicht konsistent genug eingeführt habe halte ich für kurzssichtig. Gibt es da eigendlcih einen nsinnvollen grund das zu verwerfen? Nur weil man es in der schule so gelernt hat? naja ich persöhnlich halte die umkehrung der vererbungsrichtung für sinnvoll.
wobei mich störts kaum, da ich eh oop noch nei gebraucht hab ^^.
grüße stfu&thnk (nicht signierter Beitrag von 91.13.139.219 (Diskussion) 22:22, 15. Dez. 2010 (CET))
- Der Punkt ist, dass das Umkehren der Vererbungsbeziehung auch gegen das LSP verstößt und so somit u.U. Probleme mit der Polymorphie kriegen kannst. Zudem ist das Problem genereller Natur und nicht nur auf geometrische Formen beschränkt. Alle Lösungsansätze haben ihre Nachteile. Es gibt kein Patentrezept und so heißt die Antwort auf die Frage nach dem Kreis-Ellipse-Problem wie so oft "Kommt drauf an" . In manchen Programmen mag die Umkehrung der Vererbungsbeziehung eine praktikable Lösung sein. In anderen nicht. Bei Kreis-Ellipse und Rechteck-Quadrat würde ich die Lösung mit je einer Klasse (Ellipse und Rectangle) mit passenden Methoden isCircle(), isSquare() und scale() bevorzugen. Aber das kommt auch drauf an, wie letztendlich die Klassen verwendet werden sollen... --Der Hâkawâti ✉ 13:34, 29. Dez. 2010 (CET)
- Jedenfalls ist es falsch, dass dieses Modell komplett verworfen wurde. In Java ist das Modell üblich, was ich auch soeben im Artikel eränzt habe. -- 129.247.247.238 13:00, 13. Jul. 2011 (CEST)
Spezifikation, dass die Größenanpassung fehlschlagen kann
[Quelltext bearbeiten]Wenn dies nur für den Kreis und nicht für die Ellipse gilt, dann ist das ebenfalls ein Verstoß gegen das Liskovsche Substitutionsprinzip, egal auf welche Ebene dies definiert wird. Wenn es nur um die Defintitionsebene geht, könte man ja die Spezifikation, dass die Änderung einer Achse auch auf die andere wirkt, auf der Ellipsenebene definieren, für den Fall, dass die Ausgangsellipse bereits ein Kreis ist. rairai 20:13, 9. Jan. 2013 (CET) (ohne Benutzername signierter Beitrag von Ra-raisch (Diskussion | Beiträge))
- Das sehe ich anders. Wenn die Spezifikation einer Elipse sagt, dass das Skalieren schiefgehen kann (aber nicht muss), und in Ellipse geht es nie schief, sondern nur ggf. in Kreis, ist das LSP gewahrt, denn die Subklasse hält sich an den Vertrag der Superklasse. Zum zweiten Punkt: Ja, es wäre auch möglich, die Spezifikation für skaliereX und skaliereY entsprechend an zu passen. Ob das nun besser ist, hängt vom konkreten Fall ab. --Der Hâkawâti ✉ 16:47, 11. Jan. 2013 (CET)
Ausbaufähig
[Quelltext bearbeiten]Der Artikel ist noch ausbaufähig.
- Wer hat das Problem erstmals formuliert? Zu welchen Zweck?
- Es ist Kontext nötig, um zwischen den einzelnen Lösungsmöglichkeiten abwägen zu können. Das könnte man mehr herausstellen. Je nach konkretem Fall ist eine andere Lösung angebracht. Hier wären detailliertere Beispiel sinnvoll.
- Hilfreich wäre auch, aufzuzeigen, wie sich das Problem in der konkreten Softwareentwicklung manifestiert. Klassen für Kreise und Ellipsen schreibt man so selten, aber dennoch ist das Problem relevant. Um also zu zeigen, dass das nicht nur ein akademisches Gedankenspiel ist, wären Beispiele sinnvoll.
- Weitere Lösungsmöglichkeiten ergeben sich außerdem dadurch, dass man die Klasse(n) immutable macht.
Ich hab momentan leider keine Zeit, hier was nach zu tragen. Aber wenigstens mal fürs Protokoll, was mir so einfällt... --Der Hâkawâti ✉ 16:47, 11. Jan. 2013 (CET)
- Ich habe im Moment leider auch keinen Kopf dafür. Die von Dir angesprochenen Punkte sind interessant, einfach wird es aber vermutlich nicht, etwas dazu zu finden. Den letzten Punkt verstehe ich allerdings nicht. Was soll immutable zu diesem Problem beitragen?--Cactus26 (Diskussion) 18:02, 11. Jan. 2013 (CET)
- Wenn eine Klasse immutable ist, wird jede verändernde Methode einfach ein neues Objekte zurück liefern. Somit kann eine skalieren-Methode eine gültige Invariante nicht verletzen. Kreis.skaliereX() würde also eine Ellipse zurück liefern und gut. Das ist jetzt nur ein Beispiel. Man könnte die Entscheidung mutable vs. immutable quasi zu jeder der bereits genannten Lösungen diskutieren. Letztendlich hat auch das natürlich wieder seine Vor- und Nachteile. Und zwar nicht nur in Bezug auf das LSP, sondern insbesondere auch in Bezug auf das Zeitverhalten. Je nach Kontext kann immutable hier sehr positiv, aber auch sehr negativ sein. --Der Hâkawâti ✉ 09:43, 14. Jan. 2013 (CET)
- Ich bin nicht sicher, ob nicht noch immer ein Verstoß gegen das LSP vorliegt, wenn eine Methode SkaliereX statt einer Instanz der eigenen Klasse eine der Basisklasse zurückgeben muss. Formal würde ich sagen "ja", allerdings tun sich Programmiersprachen ja mit der Vererbungshierarchie bei Typen von Rückgabeparametern ohnehin schwer, so dass die meisten Sprachen hier ohnehin nur den Basistyp "versprechen" könnten. Praktische Probleme hätte der Lsg.ansatz natürlich auch eine ganze Menge, aber das weißt Du ja, Du hast ja schon eins skizziert. Um fundierter auf Deine Idee antworten zu können, müsste ich mich aber erst wieder detaillierter mit der Geschichte befassen.--Cactus26 (Diskussion) 10:16, 14. Jan. 2013 (CET)
- Einen Verstoß gegen das LSP sehe ich nicht. Jedes Stück Code, das mit ner Ellipse umgehen kann, kann auch mit nem Kreis umgehen. Das Verhalten wäre absolut identisch. LSP ist somit gewahrt.--Der Hâkawâti ✉ 10:35, 15. Jan. 2013 (CET)
- Ja, ich denke, Du hast Recht.--Cactus26 (Diskussion) 10:54, 15. Jan. 2013 (CET)
- Einen Verstoß gegen das LSP sehe ich nicht. Jedes Stück Code, das mit ner Ellipse umgehen kann, kann auch mit nem Kreis umgehen. Das Verhalten wäre absolut identisch. LSP ist somit gewahrt.--Der Hâkawâti ✉ 10:35, 15. Jan. 2013 (CET)
- Ich bin nicht sicher, ob nicht noch immer ein Verstoß gegen das LSP vorliegt, wenn eine Methode SkaliereX statt einer Instanz der eigenen Klasse eine der Basisklasse zurückgeben muss. Formal würde ich sagen "ja", allerdings tun sich Programmiersprachen ja mit der Vererbungshierarchie bei Typen von Rückgabeparametern ohnehin schwer, so dass die meisten Sprachen hier ohnehin nur den Basistyp "versprechen" könnten. Praktische Probleme hätte der Lsg.ansatz natürlich auch eine ganze Menge, aber das weißt Du ja, Du hast ja schon eins skizziert. Um fundierter auf Deine Idee antworten zu können, müsste ich mich aber erst wieder detaillierter mit der Geschichte befassen.--Cactus26 (Diskussion) 10:16, 14. Jan. 2013 (CET)
- Wenn eine Klasse immutable ist, wird jede verändernde Methode einfach ein neues Objekte zurück liefern. Somit kann eine skalieren-Methode eine gültige Invariante nicht verletzen. Kreis.skaliereX() würde also eine Ellipse zurück liefern und gut. Das ist jetzt nur ein Beispiel. Man könnte die Entscheidung mutable vs. immutable quasi zu jeder der bereits genannten Lösungen diskutieren. Letztendlich hat auch das natürlich wieder seine Vor- und Nachteile. Und zwar nicht nur in Bezug auf das LSP, sondern insbesondere auch in Bezug auf das Zeitverhalten. Je nach Kontext kann immutable hier sehr positiv, aber auch sehr negativ sein. --Der Hâkawâti ✉ 09:43, 14. Jan. 2013 (CET)
Ableitung von "KreisElipse"
[Quelltext bearbeiten]Eine weitere Lösung wäre doch, ein Basisobjekt nur für Kreis und Elipse, welches von GrafischesElement ableitet, einzuführen. Das kann dann alle Informationen aufnehmen, die Kreis und Elipse gemeinsam haben. A998524 (Diskussion) 12:03, 1. Jun. 2013 (CEST)
- Das entspricht "Verzicht auf eine Spezialisierung für Kreis". Die Bezeichnung "KreisElipse" ist nicht sonderlich sinnvoll, da ein Kreis ja sowieso eine Elipse ist, also wieso nicht "Elipse"?--Cactus26 (Diskussion) 12:18, 1. Jun. 2013 (CEST)
Die Diskussion geht am Thema vorbei
[Quelltext bearbeiten]Die Frage, ob ein Kreis von einer Ellipse erbt, oder umgekehrt, trifft den Kern nicht. Denn das Eine ist keine Spezialisierung oder Verallgemeinerung des Anderen. Der Kreis ist ein Spezialfall der Ellipse - genau so, wie es das Quadrat zum Rechteck ist; der Spezialfall ist x=y - somit ist der 'Typ' Kreis oder Quadrat ausschließlich durch die Member der Klasse abhängig. Somit ist dies kein Fall für Vererbung. Nicht einmal kann man ein sinnvolles Interface benennen, da es ja eine Fähigkeit beschreibt und keine Eigenschaft. Somit bleibt nur übrig, eine Methode bereitzustellen, die die Frage des Spezialfalles beantwortet - sollte die umgebende Anwendung daran ernsthaftes Interesse haben. Was die Idee der Zwischenklasse angeht ist schlicht Implementierungsvererbung und auch wenigstens schlecht. Grundsätzlich sind alle Ellipsenberechnungen auch für den Kreis gültig - daher der Kreis einzig und alleine durch x=y existiert (gleiches gilt für das Quadrat). Es ist zwar ein interessantes Gedankenspiel, aber da hier weder Verallgemeinerung noch Spezialisierung vorliegt, geht es dabei eben nicht um Vererbung. (nicht signierter Beitrag von 87.175.221.230 (Diskussion) 22:38, 17. Feb. 2015 (CET))
- Ich gebe dir dahingehend recht, als dass im konkreten Fall die von dir genannte Lösung die passende ist. Unter gewissen Rahmenbedingungen kann es aber trotzdem sinnvoll sein, eine andere Lösung zu wählen. Beispiel: Angenommen es existieren mehrere Libraries zum Zeichnen von geometrischen Fomen. Für unterschiedlcihe Betriebssysteme, in unterschiedlcihen Versionen oder was auch immer. LibA kennt nur eine Methode zum Zeichnen von Ellipsen, während LibB daneben noch eine spezielle Methode zum Zeichnen von Kreisen enthält. Angenommen es hat mehr als nur einen Komfortunterschied die letztere Methode zu verwenden, wenn man Kreise zeichnen will (Performance, ... was weiß ich). Deine Aufgabe ist nun eine Abstraktionsschicht über diese beiden Bibliotheken zu setzen. Für den Kreis hast du somit echt anderen Code (if LibB then LibB.drawCircle else LibA.drawEllipse) und auf einmal macht Vererbung doch wieder Sinn. Aber es geht ja auch gar nicht um Kreise und Ellipsen. Fast jedes Vererbungsproblem lässt sich auf das Kreis-Ellipse-Problem zurückführen. Es ist ein vereinfachtes Beispiel um die Problematik zu zeigen. Sollte man Stack von Vector ableiten? Ist ein List of Car ein List of Object? Ist ein MultiSet ein Set das mehrere gleiche Elemente haben kann oder ist ein Set ein MultiSet mit der Einschränkung, dass es keine doppelten Elemente geben darf? All diese Fragen sind im Kern die selben Fragen wie man sie beim Kreis-Ellipse-Problem diskutieren kann. Und wenn man dieses Problem mal durchdrungen und die möglichen Lösungen verstanden hat, kann man damit auch diese echten Fragen beantworten.--Der Hâkawâti ✉ 09:58, 19. Feb. 2015 (CET)
Verzicht auf eine Vererbungsbeziehung = = Erweiterung der Vererbungshierarchie
[Quelltext bearbeiten]So wie momentan der Text in Lösungsvorschläge unterscheiden sich die Lösungen für "Verzicht auf eine Vererbungsbeziehung" und "Erweiterung der Vererbungshierarchie" nicht: Keine der beiden Klassen erbt von der anderen sondern beide erben gleichberechtigt von einer gemeinsamen Basisklasse entspricht Es wird eine neue (Basis-)Klasse OvalesElement eingeführt, die von der übergeordneten Basisklasse GrafischesElement erbt und als Basisklasse für Kreis und Ellipse dient. Der Einwand, dass der Unterschied darin liegt, ob die Basisklasse nur die GrafischesElement-Klasse ist oder sich speziell auf Kreis+Ellipse bezieht wird durch folgenden Satz angefochten: Es sollte also angestrebt werden, in diese gemeinsame Basisklasse möglichst viele der Gemeinsamkeiten unterzubringen. --217.115.72.103 16:26, 7. Dez. 2016 (CET)
Verzicht auf die Veränderbarkeit
[Quelltext bearbeiten]Habe folgenden Abschnitt (zunächst einmal) wieder entfernt:
- Verzicht auf die Veränderbarkeit: Wenn die Ellipse selbst unveränderlich (immutable) ist und die Methoden zur Veränderung der Halbachsen damit auch für die davon abgeleitete Klasse Kreis nicht existieren, sondern nur beim Konstruieren der Instanzen festgelegt werden können, verschwindet das Problem.
Gründe:
- Es ist keine Quelle angegeben.
- Bei Konstruktion besteht das Problem weiterhin, man könnte eine Ellipse mit zwei gleichen Halbachsen konstruieren. Als Abhilfe fiele mir da nur eine Exception ein, das wäre meiner Meinung nach aber kein diskutierungswürdiges Design.
--Cactus26 (Diskussion) 08:29, 23. Okt. 2020 (CEST)
Mehrfachvererbung?
[Quelltext bearbeiten]Habe ich es überlesen (oder nicht verstanden?), oder geht der Artikel überhaupt nicht auf die Möglichkeit der Mehrfachvererbung ein?
- Kreis kann von Ellipse UND XYSymmetrischesGrafischesObjekt erben.
- Quadrat kann von Rechteck UND XYSymmetrischesGrafischesObjekt erben.
(Mehrfachvererbung unterstützen halt leider nur die guten Sprachen) --2003:DE:F15:1A00:D4BA:A579:CA87:AA21 17:16, 12. Apr. 2022 (CEST)
- Mehrfachvererbung löst nicht das Problem, auch wenn ein Kreis gleichzeitig von Ellipse und Symmetrisches... erbt, erbt er von Ellipse immer noch die Methoden zum separaten Skalieren der Halbachsen und man kann eine Kreisinstanz somit nachträglich zu einer Ellipse machen. Man kann zwar in machen Sprachen bei Vererbung Methoden der Basisklasse "verstecken", dass hat aber nur Dokumentationscharakter, denn es sollte immer möglich sein, bei Laufzeit ein Objekt einer spezialisierenden Klasse als Basisklasse aufzufassen und sich nicht dafür zu interessieren, was es eigentlich ist.--Cactus26 (Diskussion) 14:47, 16. Apr. 2022 (CEST)