Momentan unternehme ich erste Programmierschritte in Python und denke, die eigentlichen Grundlagen verstanden zu haben, einschließlich OOP, Klassen und Methoden. Was ich aber überhaupt nicht verstehe: Woher weiß ich wie ich meinen Code in welche Klassen und Methoden zu unterteilen habe? (ich möchte in Kodi ein Video-Addon programmieren, das vom Umfang her kaum mehr als Skripte sind, ausgedruckt weniger als ein Dutzend DIN A4-Seiten. Bis jetzt ist das alles nur mit Funktionen programmiert, das funktioniert, scheint aber unschön zu sein. Als Vorlage dient https://github.com/romanvm/plugin.video.example).
Tim schrieb: > Was ich aber überhaupt nicht verstehe: Woher weiß ich wie ich meinen > Code in welche Klassen und Methoden zu unterteilen habe? Erfahrung. Prinzipiell sollen die "tiefsten" Klassen und Methoden möglichst unspezifisch sein. Mit jeder weiteren Schicht wirds dann spezifischer. Auch sollte die sich das, was eine Methode tut mit einem möglichst passenden Verb beschreiben lassen - welches dann auch für den Methodennamen verwendet werden soll. Also statt
1 | doWork() |
lieber
1 | read() |
2 | parse() |
3 | sort() |
4 | write() |
Hintergründe sind einerseits, dass man unspezifischere Klassen & Methoden evtl. für was anderes wiederverwenden kann. Und es vereinfacht die Fehlersuche. Wenn z.B. bei obigen Beispiel die Werte nicht richtig sortiert sind, sucht man in der "sort" Methode. Wahrscheinlich bequemer als 3/4 der "doWork" Methode durchzuarbeiten. BTW: Buchempfehlung: Weniger schlecht programmieren - von Katarina Passig u.A.
:
Bearbeitet durch User
Tim schrieb: > Bis jetzt ist das alles nur mit Funktionen programmiert, das > funktioniert, scheint aber unschön zu sein. Also hast du funktionierenden Code, den du jetzt schöner machen willst? Das ist doch eine dankbare Ausgangsituation zum lernen. Hast du mehrere nahezu identische Codeabschnitte? -> In eine Methode packen, die kleinen Unterschiede über Parameter handeln. Tim schrieb: > Woher weiß ich wie ich meinen > Code in welche Klassen und Methoden zu unterteilen habe? Wie Matthias sagt, Erfahrung. Es gibt nicht die eine Schritt-für-Schritt Anleitung. Das Ziel sollte eben sein, dass du den Überblick nicht verlierst und auch in ein paar Monaten wieder verstehst, wie dein Code funktioniert. Das heißt nicht unbedingt, dass man sich auf Zwang irgendwelche Klassen aus den Fingern saugen muss. Eine Klasse die nichts repräsentiert ist das Äquivalent zur Krimskrams-Schublade im echten Leben. Sieht aus als hätte man aufgeräumt, macht Dinge wiederzufinden aber nicht einfacher.
Tim schrieb: > Was ich aber überhaupt nicht verstehe: Woher weiß ich wie ich meinen > Code in welche Klassen und Methoden zu unterteilen habe? 3 Antworten dazu: 1. Python selbst stellt hier überhaupt keine Anforderungen. Das gehört zu den schönen Eigenschaften dieser Sprache: Ob du Klassen (oder auch überhaupt Funktionen) bildest, bleibt dir grundsätzlich selbst überlassen. 2. Sofern man auf Bibliotheken oder allgemein bereits vorhandenen Code aufbaut, könnte man gezwungen sein, mit Klassen zu hantieren, z.B. von einer bereits existierenden Klasse zu erben und dann bestimmte Methoden zu überschreiben. Ein einigermaßen einfaches Beispiel findest du bei exceptions: Wenn du eine eigene exception haben willst, musst du selbst etwas von der Klasse Exception (oder BaseException, aber meistens die falsche Wahl ...) ableiten. 3. Dann bleibt noch die Situation, dass du selbst objektorientiert schreiben willst. Dazu schaust du dir am besten mal Bücher zum Thema objektorientierte Analyse und Design an, außerdem viel möglichst realen Code. Ein gutes Gespür, wie fein oder grob Klassen gebildet werden sollten, entwickelst du nur mit Erfahrung.
Tim schrieb: > Was ich aber überhaupt nicht verstehe: Woher weiß ich wie ich meinen > Code in welche Klassen und Methoden zu unterteilen habe? Wie schon jemand schrieb, Erfahrung. Aber nehmen wir mal die ganz alte Schule: Klassen sind Baupläne für Objekte. Objekte sind Instanzen einer Klasse. Objekte repräsentieren (virtuell) reale oder abstrakte Dinge. An dem Punkt kommen dann so typische Beispiele für Objekte wie Auto, Reifen, Rechteck, Linie, Server, Geldautomat. Praktisch heißt das, du siehst dir dein Problem an und arbeitest heraus welche Dinge bei deinem Problem eine Rolle spielen. Danach bildest du die Klassen. Objekte kann man bitten für das Objekt typische Dinge zu tun oder Fragen über sich zu beantworten. Beispiel: Auto->anfahren(), Auto->bremsen(), Auto->welcheFarbeHastDu(). Was ein Objekt tun kann und auf welche Fragen es antworten kann wird durch Methoden beschrieben. Also bekommen deine Klassen (die Baupläne für Objekte sind), jeweils die Methoden die für die jeweiligen Objekte typisch sind und die für die konkrete Problemlösung nötig sind. Das "für das Objekt typisch" ist dabei wichtig. Viele OO-Programme halten sich nicht dran und es kommt Müll raus bei dem Klassen/Objekte nur zufällige Gruppierungen von Methoden sind. Ebenso ist "für die konkrete Problemlösung" wichtig. Beispiel: Wenn dein virtuelles Auto nur fahren und anhalten können muss wirst du, weil es einfacher ist, keine Methoden zum Blinken oder zum Betätigen der Fenster schreiben. Es geht, bis auf Ausnahmen, nicht darum ein reales oder abstraktes Ding vollständig im Rechner abzubilden. Ausnahmen siehst du bei Bibliotheken und Frameworks. Die müssen mehr anbieten als in einer einzelnen Anwendung benötigt wird um möglichst viele Anwendungen zu unterstützen.
Tim schrieb: > Was ich aber überhaupt nicht verstehe: Woher weiß ich wie ich meinen > Code in welche Klassen und Methoden zu unterteilen habe? Für einfache Projekte kann es helfen, als Text auszuformulieren was man möchte: Ich habe ein Auto. Ein Auto ist ein Sonderfall eines Kraftfahrzeuges. Ein Kraftfahrzeuges hat eine Motorleistung und kann fahren (vorwärts und rückwärts), lenken (rechts und links) und bremsen. Um fahren zu können, braucht es mindestens zwei Achsen mit jeweils mindestens einem Rad, mindestens eine Achse lenkbar. Ein Auto hat zwei Achsen mit zwei Rädern, eine davon lenkbar. Im Gegensatz zum generischen Kraftfahrzeug hat es auch eine Karosserie, mit Lack in einer bestimmten Farbe. Kraftfahrzeug: - Eigenschaften: Leistung - Member: Achsen[] - Methoden: fahre(richtung), lenke(richtung), bremse() Achse: - Member: Räder LenkbareAchse (erbt von Achse): - Eigenschaften: Ausrichtung - Member: Räder[] - Methoden: lenke(richtung) Auto (erbt von Kraftfahrzeug, implementiert Karosserie): - Eigenschaften: Leistung, Farbe - Member: Achsen[2] = { Lenkbare Achse(), Achse() }, Karosserie - Methoden: fahre(richtung), lenke(richtung), bremse() Wüstenbuggy (erbt von Kraftfahrzeug): - Eigenschaften: Leistung - Member: Achsen[2] = { Lenkbare Achse(), Achse() } - Methoden: fahre(richtung), lenke(richtung), bremse() Radlader (erbt von Kraftfahrzeug, implementiert Karosserie): - Eigenschaften: Leistung, Farbe - Member: Achsen[2] = { LenkbareAchse(), LenkbareAchse() }, Schaufel - Methoden: fahre(richtung), lenke(richtung), bremse(), hebeSchaufel(richtung) Karosserie: - Eigenschaften: Farbe -- Praktikabilität dieser Methode hängt vom Anwendungsfall ab.
Das kommt durch Erfahrung und jahrelanges Programmieren. Erst dann kann man Abschätzen, ob die Klassenstruktur hilfreich ist oder mehr Probleme bei Änderungen macht. Dazu gehört dann auch die Reflektion: "Dieses Konstrukt, was ich vor 5 Jahren gemacht habe, war vollkommen überdimensioniert". Bei nächsten Mal macht man es einfacher. Ich habe z.B. bei Kollegen eine Vererbungsstruktur mit 5 Ebenen gesehen. Da blickt heute keiner mehr durch. Aber das muss man erst einmal selber erleben.
Danke für die bisherigen Kommentare. Welches Buch/Tutorial mit praxisnahen Beispielen käme noch infrage? Geplante Anwendung --> umgesetzte Klassenstruktur
Wenn ich das richtig gelesen habe, willst du ja "nur" ein Kodi-PlugIn programmieren, bist also nicht im professionellen Umfeld unterwegs? Dann mach dir nicht zu viele Gedanken, leg einfach mal los. Wenn du klein anfängst und dein Projekt nach und nach wächst, wird das auch mit der Klassenstruktur. Du könntest ggf. auch verraten, was du vorhast? Auch Matthias S. schrieb: > Hintergründe sind einerseits, dass man unspezifischere Klassen & > Methoden evtl. für was anderes wiederverwenden kann. kannst du nach hinten anstellen. Wenn du etwas aus einem Hobbyprojekt für ein anderes Projekt verwenden kannst gibt es folgende Möglichkeiten: * du erinnerst dich nicht mehr daran, es schon gemacht zu haben und machst es neu * du musst es sowieso anpassen, also reicht blödes Copy&Paste * jemand anderes hat es schon besser gemacht und auf Git od. ähnl. veröffentlicht Solltest du dich im prof. Umfeld bewegen, ist man wahrscheinlich sowieso gut beraten, sich dem existierenden aktuellen Umfeld anzupassen.
vn nn schrieb: > Für einfache Projekte kann es helfen, als Text auszuformulieren was man > möchte: Ich will Kreise und Ellipsen zeichnen. Ein Kreis is ein sonderfall einer Ellipse. Moment mal, oh, shit: https://de.wikipedia.org/wiki/Kreis-Ellipse-Problem
🐧 DPA 🐧 schrieb: > vn nn schrieb: >> Für einfache Projekte kann es helfen, als Text auszuformulieren was man >> möchte: > > Ich will Kreise und Ellipsen zeichnen. Ein Kreis is ein sonderfall einer > Ellipse. Moment mal, oh, shit: > https://de.wikipedia.org/wiki/Kreis-Ellipse-Problem Der TO steigt gerade in die OOP ein und du kommst hier mit einem der kompliziertesten Probleme der OOP daher, ganz großes Kino. @TO Einfach mal anfangen, aus Fehlern lernt man. merciless
Die Idee hinter OOP ist ja schön, es erscheint Intuitiv, Dinge zu Klassifizieren, und sich zu überlegen x ist ein y, y ist ein z, etc. Aber Ich denke es ist wichtig von Anfang an zu verstehen, das sich eben nicht alles sauber auf die Weise Abbilden lässt. In punkto Programmstrukturen baut OOP auf 3 Dinge auf: 1) Das Kapseln/Zusammenfassen zusammengehörender Daten (Objekte) 2) Das assoziieren auf diese anwendbarer Funktionen zu diesen (Methoden) 3) Erweitern bestehender Objekte, sowie das Überschreiben derer Methoden und Eigenschaften. (Vererbung) 1 Würde ich zumindest bei so ziemlich allen nicht rein funktionalen Sprachen als essenziell betrachten. 2 Kann vor allem zusammen mit 3 sehr nützlich sein. Aber 3 kann halt auch manchmal mehr Probleme bereiten, als es löst. Der Zweck von dem ganzen OOP zeug ist ja eigentlich, auf intuitivem Weg Code dublizierung zu vermeiden, und die Codequalität und Zuverlässigkeit des Programms zu erhöhen. Das kann man damit oft auch recht gut machen. Das blöde daran ist halt nur, wenn man nicht aufpasst und es übertreibt, kann man sich schnell in eine Ecke designen, und grobe Designprobleme sind dann oft viel schwieriger zu lösen, als ein paar flache Code Bugs / Fehlfunktionen. Und nur um Code zusammenzufassen und übersichtlich zu halten, braucht man nicht unbedingt das ganze OOP und Vererbung. (Stichwort gemeinsamen Code in Unterfunktionen auslagern.) Zudem bieten Sprachen heute noch unzählige andere Sprachkonstrukte, die auch ergänzend wirken können, und oft der stumpfen Vererbung vorzuziehen sind. Außerdem haben viele gute Programmierparadigmen und Strukturen, die mit OOP in Verbindung gebracht werden, damit eigentlich gar nichts zutun und können auch ohne verwendet werden. Da ich schon mal dabei bin, will ich gleich mal Werbung für (Objekt-)Interfaces machen. Damit kann man angeben, man ist Interessiert an Daten/Objekten, mit denen man gewisse Dinge machen kann, und man kann angeben, bei welchen Arten von Daten/Objekten das gemacht werden kann. (Implementieren muss man es jeweils natürlich trotzdem noch). Oft braucht man dann Vererbung nicht mehr, und ist viel flexibler, weil man sich nicht mehr überlegen muss, was ist was, sondern einfach sagen kann, was kann momentan was. Die meisten restlichen Vererbungs use-cases kann man auch loswerden, indem man eine ist-ein Beziehung durch eine hat-ein Beziehung ersetzt. Dass kann dann auch Probleme lösen, z.B. wenn unklar ist, ob X wirklich Y ist, wenn unabhängige Objekteigenschaften kollidieren, und vieles mehr. Am Ende bleiben eigentlich nicht mehr viele Fälle übrig, in denen Vererbung tatsächlich die beste Lösung ist. Unglücklicherweise ist es in OOP Kreisen aber üblich, alles ins OOP Korsett zu zwängen, was anderes wäre ja falsch und schlechter Stil. Am Ende muss man sich meistens dann halt dem anpassen, was im jeweiligen dem Gebiet üblich ist. Es gibt immer viele gute Lösungen, und meistens nicht nur den einen richtigen Weg. Man muss nur schauen, dass was man verzapft möglichst einfach Verständlich sowie von anderen erweiterbar/wartbar ist, und dass es auch zuverlässig Funktioniert. In der Regel ist am Ende weniger oft mehr.
... und wenn man nicht aus allem einen Glaubenskrieg und eine philosophische Dissertation machen muss, ist OOP einfach nur ein praktisches Werkzeug, das bei korrekter Anwendung die gewünschten Ergebnisse liefert. Das Kreis-Ellipse-Problem basiert übrigens zu mindestens 90 % auf der übertrieben vereinfachten Vorstellung, dass Vererbung mit einer "ist ein"-Beziehung in natürlicher Sprache gleichzusetzen ist. Sobald man das verstanden hat, ist es kein "Problem" mehr, eher ein lehrreiches Beispiel, warum man sich bei der Modellierung weniger auf anschauliche Vorstellungen als auf die tatsächliche Schnittstelle, die eine Klasse definiert, konzentrieren sollte.
Tim schrieb: > Welches Buch/Tutorial mit praxisnahen Beispielen käme noch infrage? > Geplante Anwendung --> umgesetzte Klassenstruktur Eins vorweg: Erst einmal solltest du dir dessen bewusst sein, dass Objektorientierung in Python kein Dogma ist. Python unterstützt neben der objektorientierten auch die prozedurale und ein Bisschen die funktionale Programmierung. Guten Python-Code zeichnet aus, dass er jedes der genannten Paradigmen dort und nur dort einsetzt, wo es auch logisch sinnvoll ist. Anders als bspw. in Java ist es in Python absolut verpönt, jedes noch so kleine Detail in eine eigene Klasse zu wickeln, nur um irgendwelchen OOP-Grundsätzen Genüge zu tun. Es gibt viele guten Python-Programme, die ohne oder mit nur ganz wenigen selbstgeschriebenen Klassen auskommen. Andererseits ist es natürlich unklug, dort, wo die die OOP sinnvoll einsetzbar ist, auf ihre Möglichkeiten und Vorteile zu verzichten. Ich habe zwar noch nie ein Python-Buch gelesen, aber nach kurzem Überfliegen erscheint mir das folgende ganz passend zu sein: "Python 3 Object-Oriented Programming" von Dusty Phillips Du kannst ja auch mal einen Blick hineinschmeißen, um zu sehen, ob es dir zusagt. Zum Schluss noch ein kurzer Tipp, wie du für den Anfang ganz leicht potentielle Objekte in deinem Programm finden kannst: Wenn du das Programm logisch in mehrere Funktionen aufgeteilt hast und dann feststellst, dass du häufig das Schlüsselwort "global" benutzen musstest, oder dass mehrere der Funktionen gemeinsame Argumente haben, ist das ein starkes Indiz dafür, dass die globalen Variablen (oder ein Teil davon) bzw. die gemeinsam genutzten Funktionsargumente, jeweils zusammen mit den Funktionen, die sie verwenden, ein Objekt bilden. Das ist natürlich nur ein ganz kleiner Aspekt der OOP. Schwieriger wird es u.a. bei der Frage nach einer optimalen Vererbungshierarchie bzw. wann Vererbung überhaupt sinnvoll ist.
Der Beginn liegt bei den Fundamenten der OOP. Dort wo Daten und Code zusammengehoeren, kann man die mit Klassen verbinden. Das ist schon sehr effizient. Vererbung kommt sehr viel speaeter, wenn in einem Projekt auffaellt, dass man aehnliche Klassen bildet.
🐧 DPA 🐧 schrieb: > Die Idee hinter OOP ist ja schön, es erscheint Intuitiv, Dinge zu > Klassifizieren, und sich zu überlegen x ist ein y, y ist ein z, etc. > Aber Ich denke es ist wichtig von Anfang an zu verstehen, das sich eben > nicht alles sauber auf die Weise Abbilden lässt. > > In punkto Programmstrukturen baut OOP auf 3 Dinge auf: > 1) Das Kapseln/Zusammenfassen zusammengehörender Daten (Objekte) > 2) Das assoziieren auf diese anwendbarer Funktionen zu diesen > (Methoden) > 3) Erweitern bestehender Objekte, sowie das Überschreiben derer > Methoden und Eigenschaften. (Vererbung) Dr. Alan Kay, der die Objektorientierung und das Fachwort dafür erfunden hat, sagt dazu das Folgende: "OOP to me means only messaging, local retention and protection and hiding of state-process, and extreme late-binding of all things." [1] Zusammengehörige Daten kann ich auch ohne OOP zusammenfassen, dazu bieten klassische Programmiersprachen wie C Strukturen (struct) und Pascal seine Records. Aber diese Sprachen bieten sprachseitig keine Möglichkeit, die Funktionen, die sie verarbeiten sollen, an ihre Datenstrukturen zu binden. Mit ein bisschen Gehacke kann man etwas Ähnliches auch in vielen nicht-OO-Sprachen wie C abbilden, aber nur sehr unelegant; IMHO gehören Deine ersten beiden Punkte jedenfalls direkt und sehr eng zusammen. Die Vererbung ist eine andere Geschichte und eine Folge aus dem zuvor Gesagten, und für die Vererbung ist es teilweise richtig zu sagen, daß sie der Deduplizierung von Code dienen. Im Grunde dient die Vererbung aber zunächst dem Ziel, ähnliche Objekte zusammenzufassen und sie typsicher zu machen. In dem beliebten Auto-Beispiel heißt das, daß ich eine Klasse Fahrzeug mit einer abstrakten Methode beschleunige() habe, und davon dann meine Klassen Auto und Motorrad ableite. Wenn nun die Businessjungs sagen, "beschleunige das Ding", dann kann ich einfach die Methode beschleunige() autrufen, und zwar unabhängig davon, ob das betreffende Dingsi jetzt ein Auto oder ein Motorrad ist. > Der Zweck von dem ganzen OOP zeug ist ja eigentlich, auf intuitivem Weg > Code dublizierung zu vermeiden, und die Codequalität und Zuverlässigkeit > des Programms zu erhöhen. Das kann man damit oft auch recht gut machen. Der tiefere Sinn der OOP ist IMHO, den Code übersichtlicher zu organisieren und die Daten sowie die Funktionen, die sie bearbeiten, zusammenzufassen. Damit kann man auch die Duplizierung von Code vermeiden, aber das ist nicht das Ziel. > Das blöde daran ist halt nur, wenn man nicht aufpasst und es übertreibt, > kann man sich schnell in eine Ecke designen, und grobe Designprobleme > sind dann oft viel schwieriger zu lösen, als ein paar flache Code Bugs / > Fehlfunktionen. Ich weiß, diese Kritik an der OOP ist nicht neu, und war angesichts jener Zeit vor zwanzig Jahren, als "Objektorientierung" ein Verkaufsargument für manche Scharlatane war und es auch noch nicht so sehr viel Erfahrung mit dem Konzept gab, durchaus auch berechtigt. Aber es erscheint mir etwas widersinnig, jemandem ein neues Paradigma nahezubringen, indem man vor historischen (und teilweise hysterischen" Irrtümern warnt. Fakt ist: die saubere Strukturierung von Code und Daten ist eine Sache der Erfahrung, der Praxis, abstraktem Denkvermögen und der Fähigkeit, sein Problem vor und während der Umsetzung immer wieder aus der Vogelperspektive zu betrachten. Das gilt allerdings nicht nur für OOP, sondern auch für imperative, prozedurale, und funktionale Programmierung. > Und nur um Code zusammenzufassen und übersichtlich zu > halten, braucht man nicht unbedingt das ganze OOP und Vererbung. Das ist ein bisschen... halbrichtig. Um die OOP sinn- und nutzbringend einsetzen zu können, muß man sie idealerweise komplett kennen. Richtig ist allerdings, daß man nicht in jedem OO-Programm alle Mittel und Möglichkeiten nutzen muß, die sie einem bietet. Ich persönlich schätze, daß etwa 70% meiner Python-Programme eigene Klassen nutzen, aber maximal 5% meiner Python-Programme nutzen zB. die Vererbung. Es ist gut seinen ganzen Werkzeugkasten zu kennen, aber trotzdem nur den sinnvollen Teil davon zu benutzen -- nur weil ich einen Hammer darin habe, muß ich ihn nicht benutzen, um eine Schraube in die Wand zu bekommen. [1] http://userpage.fu-berlin.de/~ram/pub/pub_jf47ht81Ht/doc_kay_oop_en
Tim schrieb: > Danke für die bisherigen Kommentare. > Welches Buch/Tutorial mit praxisnahen Beispielen käme noch infrage? > Geplante Anwendung --> umgesetzte Klassenstruktur Was ich dir empfehlen würde: Befasse dich mal mit Entwurfsmustern. Die Programmierbeispiele sind zwar in Java, aber das Buch ist didaktisch großartig: https://www.amazon.de/Entwurfsmuster-von-Kopf-bis-Fu%C3%9F/dp/3955619869/ref=sr_1_3?__mk_de_DE=%C3%85M%C3%85%C5%BD%C3%95%C3%91&keywords=java+von+kopf+bis+fu%C3%9F&qid=1578822471&sr=8-3 Ich kenne Python nicht, aber wenn die Sprache halbwegs etwas taugt dann sollten die Beispiele daraus auch auf Python anwendbar sein.
Ich denke, danach hast du eine recht brauchbare Vorstellung davon, welche Vorteile Klassen usw. bieten. Auch über die klasischen Beispiele, die Gegenstände im Code nachbilden wollen, hinaus.
Das hier liest du dir durch: http://openbook.rheinwerk-verlag.de/oop/ Nicht zu lange aufhalten nur damit die mal nen Überblick bekommst, dann gehst du an dein Projekt.
Bei OOP geht es um Grunde darum das mentale Modell, das ein Mensch von einem Vorgang hat, im Code abzubilden. Das erhöht die Verständlichkeit und Wartbarkeit von Code und am Ende auch die Benutzbarkeit durch den Anwender. Das ist im Grunde eine der Kernaufgaben eines Software-Entwicklers und die Grundlage von Objektorientierung: Das mentale Modell des Anwenders in der Software abzubilden. Meist wird allerdings weniger objektorientiert, sondern eher "klassenorientiert" programmiert. Also für jeden Mist eine Klasse und zum Selbstzweck völlige Eskalation mit Vererbung, Polymorphie, Kapselung und so weiter. Mit dem Ergebnis, dass sich niemand mehr im Code auskennt. Und der Benutzer wird erst recht nicht verstehen was die Software macht, weil das Interface irgendwann später schnell-schnell darüber gestülpt wird.
:
Bearbeitet durch User
P. S. schrieb: > Bei OOP geht es um Grunde darum das mentale Modell, das ein Mensch von > einem Vorgang hat, im Code abzubilden. Wir haben doch schon besprochen, dass das nicht funktioniert (siehe Kreis-Ellipse-Problem). Und ist eine Funktion nicht ein besseres Modell für einen "Vorgang"? Das ist keine Kritik an OOP, nur an dieser Vorstellung von OOP als "mentales Modell" der Wirklichkeit.
Wühlhase schrieb: > Ich kenne Python nicht, aber wenn die Sprache halbwegs etwas taugt dann > sollten die Beispiele daraus auch auf Python anwendbar sein. Wenn die Sprache etwas taugt (also nicht Java), dann sollte man keine dieser Entwurfsmuster mehr brauchen.
Dirk K. schrieb: > Der TO steigt gerade in die OOP ein und du kommst > hier mit einem der kompliziertesten Probleme der > OOP Nicht wirklich, sondern dem üblichen Problem: übermässige Klassenanzahl.
MaWin schrieb: > Nicht wirklich, sondern dem üblichen Problem: übermässige Klassenanzahl. Nein, einfach nochmal lesen, worauf ich mich bezogen habe. Da steht nichts von Klassenanzahl. Jaa, auch Trollen will gelernt sein. merciless
Dirk K. schrieb: > Da steht nichts von Klassenanzahl Aber ein Problem, wie es durch übermässige Klassenanzahl hervorgerufen wird. Das übliche Problem. Es ist Unsinn, bei OOP versuchen zu wollen "die Realität" mit möglichst filigraner Klasseneinteilung erfassen zu wollen. Dann läuft man unweigerlich früher oder später in eine Sackgasse weil in der Realitat eben nicht alles logisch ist. Man darf und sollte eine neue zusätzliche Klasse nur dann anlegen, wenn es aus programmtechnischen Gründen handfeste Argumente dafür gibt. Viele Programme sind beispielsweise mit einer einzigen Klasse "die App" gut bedient. Das ist fast wie programmieren ohne Klassen, in dem alle sonst als global deklarierten Variablen nun Membervariablen werden und alle Funktionen zu Methoden dieser Klasse werden die natürlich auf alle Members zugreifen können. Man sollte diese Umwandlung eines bisher prozeduralen Programms machen (oder gleich so starten), wenn man im selben Kontext mehrere Instanzen davon laufen lassen will. Es gibt dann also einen handfesten Grund: man kann nicht dieselbe globale Variable doppelt haben, und OOP ist hier die naheliegende und übersichtlich strukturierte Lösung. Ebenso bei weiteren Schritten: ich will Fehlerbehandlung durch Exceptions haben, dann darf ich nicht einfach aus einer Funktion herauspoltern die dynamisch Speicher allokiert hat, sondern ich muss diese Speicherallokation in eine Klasse verpacken deren Destruktor den Speicher wieder frei gibt. Auch hier gibt es einen handfesten Grund warum man eine Klasse (oder hunderte..) einführt. etc. Man hinterfrage bei jeder Klasse, ob es wirklich aus der Programmierrealität heraus einen handfesten Grund gibt, sie einzuführen. Das schlimmste was man tun kann ist beispielsweise, für jedes Datenbankfeld "Anrede", "Vorname", "Nachname", Strasse" ... eine eigene Klasse einzuführen. Da verbaut man sich jede genetische Verarbeitung. Leider führen viele OOP Kurse genau zu der Lösung, Klassen als Selbstzweck anzulegen.
tipp schrieb: > Wenn die Sprache etwas taugt (also nicht Java), dann sollte man keine > dieser Entwurfsmuster mehr brauchen. Aha...warum sollte Java denn nichts taugen? Und wie sollte eine Sprache aussehen, die zwar objektorientiert ist, aber in der keine Entwurfsmuster gebraucht werden? Was wäre in so einer Sprache denn anders? Da bin ich doch wirklich mal gespannt... Entwurfsmuster braucht man generell nicht. Aber sie machen einem das Leben erheblich einfacher. Unabhängig von der Programmiersprache. MaWin schrieb: > Nicht wirklich, sondern dem üblichen Problem: übermässige Klassenanzahl. Was für ein Unsinn...du hast den Grund, weshalb man überhaupt in Klassen aufteilt, absolut gar nicht verstanden. Ich gehe mal exemplarisch nur auf eine Perle ein: MaWin schrieb: > Man darf und sollte eine neue zusätzliche Klasse nur dann anlegen, wenn > es aus programmtechnischen Gründen handfeste Argumente dafür gibt. Klassen hat man, um einen definierten Kontext zu schaffen. Absolut unabhängig vom Rest des Programms. Eine Abstraktionsebene schaffen zu wollen (z.B. weil man eine Fremdbibliothek verwenden will und noch nicht klar ist, ob man die später evt. durch eine andere ersetzen möchte) oder einfach einen Funktionsteil abzugrenzen. Wenn du z.B. eine Eigenschaft eines (anderen) Objekts hast, das du als Integer behandeln willst aber den Wertebereich begrenzen willst. Solche Banalitäten sind Grund genug, eine neue Klasse aufzumachen.
MaWin schrieb: > Dirk K. schrieb: >> Der TO steigt gerade in die OOP ein und du kommst >> hier mit einem der kompliziertesten Probleme der >> OOP > > Nicht wirklich, sondern dem üblichen Problem: übermässige Klassenanzahl. Es kann gute gründe geben, für Kreise und Ellipsen andere Klassen zu benötigen. Das Problem liegt hier nicht bei der Anzahl Klassen, sondern bei der unnötigen/falschen Vererbung. Solange man diese hier nur nicht direkt zwischen Kreisen und Ellipsen macht, hat man das Problem nicht mehr. Aber auch sonst ist die Klassenanzahl eigentlich nie das Hauptproblem. Um noch ein anderes Beispiel zu bringen, eine Person hat eine Adresse. Es wird nicht schaden, die Adresse in eine extra Klasse auszulagern. Die Person sollte nur weiterhin nicht von Adresse erben. Ich kann da beliebig mehr Eigenschaften zusammen in Klassen auslagern, es mag weniger übersichtlich werden, aber es kann nicht so grundlegend falsch werden, wie das mit dem Einführen einer neuen Vererbung möglich wäre.
🐧 DPA 🐧 schrieb: > Aber auch sonst ist die Klassenanzahl eigentlich nie das Hauptproblem. > Um noch ein anderes Beispiel zu bringen, eine Person hat eine Adresse. > Es wird nicht schaden, die Adresse in eine extra Klasse auszulagern. Die > Person sollte nur weiterhin nicht von Adresse erben. Ich kann da > beliebig mehr Eigenschaften zusammen in Klassen auslagern, es mag > weniger übersichtlich werden, aber es kann nicht so grundlegend falsch > werden, wie das mit dem Einführen einer neuen Vererbung möglich wäre. Jetzt hör' doch bitte mal mit Deinem Kreuzzug gegen die Vererbung auf. Kein denkender Entwickler der Welt käme auf die irre Idee, eine Personenklasse von einer Adressenklasse erben zu lassen. Reale Personen haben nämlich bisweilen mehrere Adressen, anders gesagt: die Personenklasse beinhaltet eine Liste von Adressen. So würde man das ja auch in einer Datenbank modellieren, als 1:n.
Jemand schrieb: > Kein denkender Entwickler der Welt käme auf die irre Idee, eine > Personenklasse von einer Adressenklasse erben zu lassen. https://github.com/search?q=%22Person+extends+Address%22&type=code
Je nun, in den unendlichen Weiten des Netzes findet sich für jeden noch so abstrusen Blödsinn immer ein Beispiel. Oliver
:
Bearbeitet durch User
Es sind dennoch echte Entwickler, die den Fehler machen. Ausserdem ist es ein Fehler, welcher Anfängern gerne unterläuft.
🐧 DPA 🐧 schrieb: > Es sind dennoch echte Entwickler, die den Fehler machen. Ausserdem ist > es ein Fehler, welcher Anfängern gerne unterläuft. Köche schneiden sich im Laufe ihres Lebens öfter in die Finger als andere Menschen, außerdem passiert das jungen Köchen häufiger: Lasst uns Messer verbieten und die Schweinekeule im ganzen über das Feuer hängen, dann kann dies nicht mehr passieren. merciless
Es ist sinvoll, jemanden, der zum ersten mal Kocht darauf Hinzuweisen, dass das Messer scharf ist. Ausserdem gibt man Kleinkindern bewusst noch keine Messer in die Hand, sondern erst denjenigen, die Messer bereits verstehen und vermutlich damit umgehen werden können.
mh schrieb: > Wir haben doch schon besprochen, dass das nicht funktioniert (siehe > Kreis-Ellipse-Problem). Ja. Wenn man sich auf mathematische/theoretische Spitzfindigkeiten statt auf die eigentliche Anwendung und den Benutzer konzentriert, kann man durchaus die Meinung vertreten, "dass das nicht funktioniert".
mh schrieb: > P. S. schrieb: >> Bei OOP geht es um Grunde darum das mentale Modell, das ein Mensch von >> einem Vorgang hat, im Code abzubilden. P. S. schrieb: > mh schrieb: >> Wir haben doch schon besprochen, dass das nicht funktioniert (siehe >> Kreis-Ellipse-Problem). > > Ja. Wenn man sich auf mathematische/theoretische Spitzfindigkeiten statt > auf die eigentliche Anwendung und den Benutzer konzentriert, kann man > durchaus die Meinung vertreten, "dass das nicht funktioniert". Ich kann nichts dafür, dass sich mein "mentales Modell" im Allgemeinen gut mit der Mathematik verträgt.
Das Kreis-Ellipse Problem hat man immer, wenn die abgeleitete Klasse einschränkungen, eine fehlende Aktion oder Eigenschaft gegenüber der Basisklasse hat. Mit Mathematik hat das nichts zutun. Ist ein Pinguin ein Vogel?
1 | for vogel in voegel: |
2 | vogel.takeoff() |
Pinguine fliegen aber! Halt in einem anderen Medium. mh schrieb: > Ich kann nichts dafür, dass sich mein "mentales Modell" im Allgemeinen > gut mit der Mathematik verträgt. Mag gerne sein. Man kann mit solch einer theoretischen Frage die Praxis auch verkomplizieren. Nicht das es nicht wertvoll wäre das Kreis-/Ellipse-Problem zu kennen, in der Praxis wird einem dieses Problem aber wohl er nicht so oft begegnen und wenn, wird man es - der Anwendung gerecht - umschiffen können. OOP ist ein Konzept, um vieles besser verständlich, einfacher zu implementieren,... usw. usf. zu machen. Man kann das Konzept aber auch versuchen mit aller Gewalt jedem Problem aufzusetzen, feststellen dass das nicht immer so gut funktioniert und dann das ganze Konzept doof finden...
🐧 DPA 🐧 schrieb: > Das Kreis-Ellipse Problem hat man immer, wenn die abgeleitete Klasse > einschränkungen, eine fehlende Aktion oder Eigenschaft gegenüber der > Basisklasse hat. Mit Mathematik hat das nichts zutun. Ist ein Pinguin > ein Vogel? >
1 | > for vogel in voegel: |
2 | > vogel.takeoff() |
3 | >
|
Die Annahme, dass alle Vögel können fliegen, ist falsch (und das weisst du genau). https://de.wikipedia.org/wiki/V%C3%B6gel merciless
Matthias S. schrieb: > Pinguine fliegen aber! Halt in einem anderen Medium. Und "wahr" ist "falsch"! Nur halt in negativer Logik. > OOP ist ein Konzept, um vieles besser verständlich, > einfacher zu implementieren,... usw. usf. zu machen. Der Kritikpunkt war aber nicht OOP allgemein, sondern die VERERBUNG.
Dirk K. schrieb: > Die Annahme, dass alle Vögel können fliegen, > ist falsch (und das weisst du genau). Kann es sein, dass Du Daniels Beispiel nicht verstanden hast?
Egon D. schrieb: > Matthias S. schrieb: > >> Pinguine fliegen aber! Halt in einem anderen Medium. > > Und "wahr" ist "falsch"! Nur halt in negativer Logik. Was aber nichts daran ändert, dass der Pinguinexperte von einem Flug spricht. Was kommt jetzt rein in das Programm? Das was der Pinguinexperte oder das was der Programmierexperte sagt? Egon D. schrieb: > Der Kritikpunkt war aber nicht OOP allgemein, sondern > die VERERBUNG. Dann ersetze halt OOP mit "Vererbung".
Egon D. schrieb: > Kann es sein, dass Du Daniels Beispiel nicht > verstanden hast? Nein, was ich schon am 09.09. kritisiert habe: Daniel konfrontiert einen Einsteiger in Sachen OOP mit einem der kompliziertesten Design-Probleme in der OOP. Und der Einsteiger wird nicht verstehen können, um was es da geht. Ich sage: Lauf mal los und designe Klassen, wie du meinst. Irgendwann wird er eine Basisklasse Vogel mit einer Methode fliege() haben und den Pinguin implementieren wollen: DANN wird er erkennen, dass es ein Problem ist und genau DANN kann man darüber diskutieren. Ich zähle mich zu den Puristen: Ableitungen nur von Interfaces und abstrakten Basisklassen (letzteres sehr selten) - Exception-Klassen sind eine Ausnahme. https://en.wikipedia.org/wiki/Composition_over_inheritance merciless
:
Bearbeitet durch User
Dirk K. schrieb: > Egon D. schrieb: >> Kann es sein, dass Du Daniels Beispiel nicht >> verstanden hast? > > Nein, was ich schon am 09.09. kritisiert habe: > Daniel konfrontiert einen Einsteiger in Sachen OOP > mit einem der kompliziertesten Design-Probleme in > der OOP. Nein, überhaupt nicht. Daniel versucht nur daraufhinzuweisen, dass dieses angeblich so komplizierte OOP-Problem nur eine zwangsläufige, aber abstruse Folgerung aus einer (m.E.) völlig abseitigen Auffassung von OOP ist. Wer in Automatentheorie beschlagen ist, kann sich leicht überlegen, dass "Objekte" (im Sinne der OOP) einfach Automaten sind; die zur Programmlaufzeit aufgebaute Objekthierarchie ist also einfach als Automatennetz anzusehen. Vererbung ist für das Grundverständnis dieses Sachverhaltens erstmal nicht erforderlich. Vererbung mag eine nützliche Idee sein, das will ich nicht beurteilen, aber sie gehört ganz sicher nicht zum logischen Kern der OOP. > Und der Einsteiger wird nicht verstehen können, > um was es da geht. Das ist aber nicht schuld des Einsteigers, sondern einer völlig verqueren Auffassung von OOP. :) > Ich sage: Lauf mal los und designe Klassen, wie > du meinst. Irgendwann wird er eine Basisklasse > Vogel mit einer Methode fliege() haben und den > Pinguin implementieren wollen: DANN wird er > erkennen, dass es ein Problem ist und genau > DANN kann man darüber diskutieren. Naja, in der Datenbanktheorie hat man relativ frühzeitig verstanden, dass Hierarchien bzw. Bäume nicht das alleinseligmachende Rezept für die Strukturierung von Dingen und ihren Eigenschaften ist, und hat die Normalformen- theorie entwickelt. Insofern wundert mich nicht wirklich, dass sich eine Vererbungs- HIERARCHIE nicht als praxisgerecht erweist. Genau DAS ist m.E. auch der Kern von Daniels Kritik: Dass nämlich die Vererbung nicht als technisches Hilfsmittel dargestellt wird, sondern als einfacher und offensichtlicher Weg, die Verhältnisse des realen Lebens im Computer abzubilden -- und genau letzteres stimmt halt nicht.
Egon D. schrieb: > Insofern wundert mich nicht wirklich, dass sich eine Vererbungs- > HIERARCHIE nicht als praxisgerecht erweist. Genau DAS ist m.E. auch der > Kern von Daniels Kritik: Vielleicht würde man heute statt von Vererbung eher von Teilen oder Plagiat sprechen. Kein "ist ein" sondern eher "kann auch" bzw. "hat auch". Die ganze "Uhu ist ein Vogel" Metapher scheitert einfach daran, dass es die platonische "Idee" eines Vogels nicht gibt, auch nicht die Unterscheidung in akzidenz und Essenz. Ein "Vogel" ist einfach nur ein willkürliches subset der realen Ausprägungen aller Vögel.
@Egon D. (egon_d) Du interpretierst da etwas zu viel in meine bisherigen Aussegan hinein.
🐧 DPA 🐧 schrieb: > Das Kreis-Ellipse Problem hat man immer, wenn die abgeleitete Klasse > einschränkungen, eine fehlende Aktion oder Eigenschaft gegenüber der > Basisklasse hat. Mit Mathematik hat das nichts zutun. Ist ein Pinguin > ein Vogel? >
1 | > for vogel in voegel: |
2 | > vogel.takeoff() |
3 | >
|
Ich fürchte, der ganze Denkansatz ist ein bisschen... zu kurz gedacht, und dies gilt sowohl für das Beispiel mit den Pinguinen, als auch für das Kreis-Ellipsendings. Natürlich, für den Biologen ist der Pinguin ein Vogel und für den Mathematiker der Kreis eine Sonderform der Ellipse. Es gibt aber keinen Grund der Welt, warum ein Entwickler oder Softwaredesigner sich daran orientieren, also ein Pingu von BaseVogel oder der Kreis von der Ellipse erben muß. Ein kluger Entwickler würde sowas entweder beim Erstentwurf oder spätestens beim Refactoring anders modellieren, für den Vogel also:
1 | BaseVogel |
2 | | | |
3 | | +- LaufVogel |
4 | | +- Pinguin |
5 | | +- Strauß |
6 | | +- Emu |
7 | | +- Nandu |
8 | | +- Kiwi |
9 | | |
10 | +- FlugVogel |
11 | +- Amsel |
12 | +- Drossel |
13 | +- Fink |
14 | +- Star |
Der Grundfehler bei Deinem Vögelbeispiel liegt darin, anzunehmen, daß alle Vögel fliegen können. Genau das ist aber nicht der Fall, wie Du meinem Modell entnehmen kannst. Nebenbei: in Programmiersprachen, die ihre Entwicklergemeinde nicht für zu dämlitsch dafür halten, gibt es natürlich auch noch die Möglichkeiten der Mehrfachvererbung. Damit könnte man einen Vogel zum Beispiel einfach als nicht schwimm-, tauch- und flugfähigen Vogel definieren, und die Flug-, Schwimm- und Tauchfähigkeiten als weitere Klassen. So würde unser Pinguin von BaseVogel, SchwimmMixin und TauchMixin erben, unsere Ente dagegen von BaseVogel, Flug- und SchwimmMixin, und die Amsel von BaseVogel und FlugMixin. Alles absolut sauber modelliert, und je nach Anforderungen (und ggf. globaler oder lokaler Konfiguration) kann ein Aufruf der Methode takeoff() für nicht flugfähiges Geflügel entweder eine Exception werfen, oder die Eigenschaft Höhe auf einen Wert != 0 setzen und eine 0 zurückgeben, oder... ja, ganz genau. Viel wichtiger, als OO-Einsteiger vor den Gefahren und Fallstricken der OO zu warnen, ist es daher IMHO, ihnen zu raten, keine Angst vor einem Refactoring zu haben, wenn die gewählte Architektur sich als suboptimal und nicht zu den Anforderungen passend entpuppen sollte. Es kostet nämlich auf mittlere und lange Sicht ein Vielfaches, um ein verkorkstes Design herumzuentwickeln, als seine ursprünglichen Designfehler beizubehalten.
@Jemand Genau diese Überlegungen sind es, die das Beispiel hervorrufen sollte. Bravo!
Da wir hier jetzt ins akademische Abdriften: So in etwa wäre mein erster Entwurf. So etwas wie die abstrakte Basisklasse Bird würde ich auch nur dann einbauen, wenn das technisch notwendig sein sollte. Ich gehe hier auch davon aus, dass es nicht unbedingt wichtig ist, auf welchem Tier Methoden aufgerufen werden, sondern dass immer auf den Interfaces operiert wird. An der Klasse Tuna kann man auch erkennen, dass es Methoden gibt, die für Vögel und Fische Sinn machen können.
1 | interface IEggLayingAnimal |
2 | { |
3 | void LayEgg(); |
4 | } |
5 | |
6 | interface IFlyingAnimal |
7 | { |
8 | void Fly(); |
9 | } |
10 | |
11 | interface ISwimmingAnimal |
12 | { |
13 | void Swim(); |
14 | } |
15 | |
16 | abstract class Bird |
17 | { |
18 | private Color FeatherColor; |
19 | } |
20 | |
21 | class Penguin : Bird, IEggLayingAnimal, ISwimmingAnimal |
22 | { |
23 | } |
24 | |
25 | class Owl : Bird, IEggLayingAnimal, IFlyingAnimal |
26 | { |
27 | } |
28 | |
29 | class Tuna : IEggLayingAnimal, ISwimmingAnimal |
30 | { |
31 | } |
merciless
Jemand schrieb: > Ein kluger Entwickler würde > sowas entweder beim Erstentwurf oder spätestens beim Refactoring anders > modellieren, für den Vogel also: Ja, kann man machen. Das teilt die Vögel in flugfähige und -unfähige. Nur leider gibt es dutzende "Teilungen", die genauso Sinn machen und quer durch diese Teilung laufen. Tag-Nacht, Tier- oder Planzenfresser, Laufen oder Hüpfen, bauen Nester oder nicht … und das alles mit einem Graubereich dazwischen. Das ist der Grund, warum das nur in akademisch einfachen Beispielen funktioniert. In der Praxis brauchst Du dann doch eine Überklasse Vögel (alle "fliegen", wenn auch manche nur vor die Füße) oder nur eine Basisklasse (2 Beine, legen Eier, aber können weder fliegen noch laufen oder hüpfen)
Man kann aber auch einfach gucken, was man braucht. Wenn man bei den Vögeln z.B. "fliegen" nicht braucht, sondern nur "lege Ei", warum sollte ich mir dann den Stress um das "fliegen" machen? Weil das in ferner Zukunft, evtl., u.U., vllt., irgendwann einmal, gebraucht werden könnte?
Nunja, oft hat man die umgekehrte Situation. Man hat viele Flugfähige Vögel, und irgendwo ist Logik, die bei Vögeln die Flugfunktion aufruft. Wenn dann alles schon fertig ist kommt jemand, und will noch einen Pinguin, einen Dodo und einen Kiwi haben...
🐧 DPA 🐧 schrieb: > Nunja, oft hat man die umgekehrte Situation. Man hat viele Flugfähige > Vögel, und irgendwo ist Logik, die bei Vögeln die Flugfunktion aufruft. > Wenn dann alles schon fertig ist kommt jemand, und will noch einen > Pinguin, einen Dodo und einen Kiwi haben... und eine Fledermaus... merciless
Dirk K. schrieb: > 🐧 DPA 🐧 schrieb: >> Nunja, oft hat man die umgekehrte Situation. Man hat >> viele Flugfähige Vögel, und irgendwo ist Logik, die >> bei Vögeln die Flugfunktion aufruft. Wenn dann alles >> schon fertig ist kommt jemand, und will noch einen >> Pinguin, einen Dodo und einen Kiwi haben... > > und eine Fledermaus... ... und dann noch eine Fliege, eine Hornisse, einen Lenkdrachen, ein Luftschiff und einen Jagdflieger? Langsam wird es albern.
Matthias S. schrieb: > Man kann aber auch einfach gucken, was man > braucht. Ähh... ja?! > Wenn man bei den Vögeln z.B. "fliegen" nicht braucht, > sondern nur "lege Ei", warum sollte ich mir dann den > Stress um das "fliegen" machen? Musst Du nicht. Verlangt niemand. > Weil das in ferner Zukunft, evtl., u.U., vllt., > irgendwann einmal, gebraucht werden könnte? Nee. YAGNI. Die Diskussion hat sich nur daran entzündet, dass oben jemand -- wie das in alten schlechten Büchern üblich war -- Vererbung als einfaches und offensichtliches Mittel zum Abbilden der Realität im Computer angepriesen hat. Einfache Vererbung führt aber zu einer Hierarchie, und von den Datenbanken her ist bekannt, dass die reale Welt nur selten als Hierarchie abgebildet werden kann. Der Pragmatiker tut genau das, was Du vorgeschlagen hast: Er modelliert zunächst im Geiste den Teil der Realität, der für ihn relevant ist, und überträgt diesen anschließend in Programmform in den Rechner.
Egon D. schrieb: > Einfache Vererbung führt aber zu einer Hierarchie, und von den > Datenbanken her ist bekannt, dass die reale Welt nur selten als > Hierarchie abgebildet werden kann. Kannst Du das bitte noch einmal in fett setzen und am besten auch noch in die entsprechenden Kapitel hier einfügen? Treffend formuliert.
Egon D. schrieb: > ... und dann noch eine Fliege, eine Hornisse, einen > Lenkdrachen, ein Luftschiff und einen Jagdflieger? > > Langsam wird es albern. Nee eben nicht. Genau das ist die Realität. Deswegen operiere ich nur auf einem Interface, dass die Methode Fly() bietet. Dann bin ich flexibel, egal was da verarbeitet werden soll. Vererbung hat ihre Berechtigung, sollte aber sehr umsichtig eingesetzt werden. Meistens gibt es bessere Lösungen. Aber das lernt man nicht in "OOP für Dummies in 3 Tagen". merciless
A. S. schrieb: > Egon D. schrieb: >> Einfache Vererbung führt aber zu einer Hierarchie, und von den >> Datenbanken her ist bekannt, dass die reale Welt nur selten als >> Hierarchie abgebildet werden kann. > > Kannst Du das bitte noch einmal in fett setzen und am besten auch noch > in die entsprechenden Kapitel hier einfügen? Treffend formuliert. Richtig ist: so etwas kann mit relationalen Datenbanken nicht sonderlich gut abgebildet werden, wobei auch das primär für relationale Datenbanken gilt. Andere Datenbanken sind entweder ohnehin hierarchisch aufgebaut, man denke da nur an Verzeichnisdienste wie OpenLDAP oder ActiveDirectory, an Spezialisten wie IBMs Information Management System oder auch die Windows Registry, an neuere NoSQL-Datenbanktypen wie MongoDB oder RestDB oder an Grafendatenbanken wie OrientDB oder Neo4j. Allerdings ist es in relationalen Datenbanken zwar ein wenig aufwändiger und manchmal nicht besonders elegant, aber auch dort kann man mit hierarchischen Datenmodellen arbeiten -- allein Joey Celko hat viele spannende Dinge zu Bäumen und Hierarchien in klassischen relationalen Datenbanken geschrieben. Fakt ist aber auch, daß nichts so einfach ist, wie es scheint: die meisten Menschen würden es auf den ersten Blick als die wohl wichtigste gemeinsame Eigenschaft von Vögeln bezeichnen, daß sie fliegen können. Trotzdem sind Dodos und Pinguine zwar Vögel, aber nicht flugfähig. Und jetzt? Sind Pinguine und Dodos jetzt keine Vögel mehr, sondern nur noch Tiere? Oder ist vielleicht nur die zugrundeliegende Annahme falsch, daß alle Vögel fliegen können? Nun, am Ende hängt es immer vom konkreten Anwendungsfall ab, ob Vererbung oder Komposition benutzt wird, welche Eigenschaften und Methoden implementiert werden, und so weiter. Sich hier ohne Kenntnis des Anwendungsfalls einfach mal festzulegen und die Vererbung zu einem Antipattern zu erklären, ist genauso zu kurz gesprungen wie sie zum Allheilmittel hochzujubeln.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.