Basisklasse für Bewegungseigenschaften – polymorph oder nicht?
-
Ja, ich muss ehrlich sagen, dass mir das momentante Design auch nicht besonders gefällt. Wegen der virtuellen Funktionen: Ich mache eine Klasse ungern polymorph, wenn ich die Polymorphie nicht nutze. Und gerade für eine Partikelklasse, die nur ein paar Attribute hat, ist
virtual
wirklich Overkill, weil es gar keinen Vorteil bringt.Mit dem Overengineering hast du völlig Recht, rapso. Ich habe in letzter Zeit ab und zu ein Design komplett über den Haufen werfen müssen, daher versuche ich hier etwas mehr im Voraus zu planen. Aber man kanns auch übertreiben... Data-Driven Design klingt jedenfalls schon mal gut, danke für den Hinweis! Ich hab das auch in der Irrlicht-Bibliothek gesehen. Nur frage ich mich, wie man da verhindern kann, dass ein Member unabsichtlich verändert wird (z.B. die bisherige Lebensdauer bei Partikeln)... Einfach in die Dokumentation schreiben?
Vielleicht noch zur Erklärung, warum ich sowas wie
PositionAttributable
und nicht ein MemberPosition
im Kopf hatte: Erstens muss man nicht jedes Mal die Zugriffsfunktionen neu schreiben und spart so Codeduplizierung, zweitens kann man positionierbare Objekte über die Basisklasse ansprechen. Ja, der Name ist blöd, sowas wiePositionable
(positionierbar) wäre vielleicht besser gewesen. Aber die Grundintention ist einigermassen verständlich?
-
Ich konnte mir nichts unter data-driven-design vorstellen: http://en.wikipedia.org/wiki/Data-driven_programming . Ich kann mir immer noch nichts darunter vorstellen.
wie man da verhindern kann, dass ein Member unabsichtlich verändert wird
Gar nicht. "Not worth the effort — encapsulation is for code, not people" oder "Encapsulation prevents mistakes, not espionage." http://www.parashift.com/c++-faq-lite/index.html 7.6 und 7.8
Aber die Grundintention ist einigermassen verständlich?
Ja, aber man kommt von vererbter Implementation ab. Besseres Design ist nur das Interface zu erben. Beispiele dafuer sind Java-Interface oder Haskells type classes. Dieser Ansatz hat sich bewaehrt, ist wohl aber noch nicht so richtig in der Welt angekommen. Natuerlich kostet sowas auch, z.B. eine vtable. Auch sollte man es nicht mit den Interface uebertreiben.
Bei deinem Partikelsystem macht dieser Ansatz wohl wenig Sinn. Aber jedes Partikel als eigenstaendiges Objekt zu modellieren wohl auch nicht.
-
knivil schrieb:
Gar nicht. "Not worth the effort — encapsulation is for code, not people" oder "Encapsulation prevents mistakes, not espionage."
Ich habe aber "unabsichtlich" und nicht "böswillig" hingeschrieben.
knivil schrieb:
Ja, aber man kommt von vererbter Implementation ab. Besseres Design ist nur das Interface zu erben.
Ja, man ist mit statuslosen Interfaces flexibler. Aber man muss die Grundimplementierung (nämlich das Attribut zu setzen und zu erhalten) jedes Mal neu schreiben, obwohl diese meist gleich bleibt. Eine Zwischenlösung wäre vielleicht eine Default-Implementierung des Interfaces.
knivil schrieb:
Aber jedes Partikel als eigenstaendiges Objekt zu modellieren [macht] wohl auch nicht [Sinn].
Warum sollte das keinen Sinn machen? Soll ich etwa jede Information einzeln abspeichern und dann je einen separaten Container für Positionen, Farben, Geschwindigkeiten, etc. haben und zueinander synchron halten? Partikel als Objekte zu behandeln ist durchaus vernünftig. Man muss ja nicht zwingend Vererbung, Polymorphie oder Data Hiding einsetzen.
-
Langsam, langsam: eine Klasse kapselt Daten und Methoden. Wenn aber nur der Partikelmanager/ -system, in dem die Partikel verwaltet werden, Position oder Geschwindigkeit setzt, dann braucht man dafuer nicht extra eine Methode in der class/struct Partikel.
-
Das Eingangsbeispiel dafür, warum das nötig wäre, die Attribut-Klasse zu überschreiben, hallte ich für falsch. In meiner Logik speichern die Kinder immer eine Position relativ zu ihrem Vater. Wenn man den Baum runterwandert, kann man ja nebenbei die Absolut-Position auf einen Stack hauen, so man sie denn braucht.
-
knivil schrieb:
Langsam, langsam: eine Klasse kapselt Daten und Methoden. Wenn aber nur der Partikelmanager/ -system, in dem die Partikel verwaltet werden, Position oder Geschwindigkeit setzt, dann braucht man dafuer nicht extra eine Methode in der class/struct Partikel.
Ja, das wäre ja auch der Vorschlag von rapso. Aber dadurch bleibt ein Partikel immer noch ein Objekt. Oder hast du mit "eigenständigem Objekt" ein Objekt gemeint, das seine Methoden selbst bereitstellt? Dann haben wir uns hier missverstanden.
Decimad schrieb:
Das Eingangsbeispiel dafür, warum das nötig wäre, die Attribut-Klasse zu überschreiben, hallte ich für falsch. In meiner Logik speichern die Kinder immer eine Position relativ zu ihrem Vater. Wenn man den Baum runterwandert, kann man ja nebenbei die Absolut-Position auf einen Stack hauen, so man sie denn braucht.
Stimmt, das wäre um einiges sinnvoller. Aber ich bräuchte trotzdem eine Funktion, welche die absolute Position bestimmt. Das könnte man vielleicht durch eine Rekursion über Parent-Zeiger lösen. Vielen Dank für den Hinweis!
-
Was ist denn ueberhaupt die Zielsetzung?
Wenn man beispielsweise 100.000 Partikel auf einem Haufen hat, wuerde man die natuerlich nicht als unabhaengige Objekte im Szene-Graphen halten und pro Objekt rekursiv die Transformation ermitteln...
-
Ja, das ging mir vorhin auch durch den Kopf. Ich glaube, ich versuche gerade, viel zu viel auf einmal zu erreichen.
Ich muss das Ganze ein wenig ordnen, dann wird auch das Design klarer... :xmas1:
-
So, und jetzt auch mal zum Thema. Ich finde, wenn man diese Attributklasse hat, dann sollte sie überall das gleiche bewirken. Sie soll ja ein eindeutige Sache, nämlich das Attribut darstellen, also sozusagen eine Garantie auf ein Ding. (Hier finde ich das aber auch als Member besser, weil das Objekt ja zwar eine Position hat, aber nicht eine Position ist. Es wäre in deinem Fall also sozusagen eine bloße Abkürzung der Schreibweise, die du durch die Ableitung bezweckst.)
Bei echten Schnittstellen hingegen (also meinetwegen pure virtual), garantiert man ja in meinen Augen eine Garantie auf eine "Fähigkeit" des konkreten Objekts. Und ich finde halt, dass deine Herangensweise die beiden Dinge irgendwie verwurschtelt... Aber ich hab selber oft genug Design-Probleme, von daher kann ich das gerade alles falsch sehen. Im Zweifel würde ich bei OpenSceneGraph abkupfern
-
Decimad schrieb:
So, und jetzt auch mal zum Thema. Ich finde, wenn man diese Attributklasse hat, dann sollte sie überall das gleiche bewirken. Sie soll ja ein eindeutige Sache, nämlich das Attribut darstellen, also sozusagen eine Garantie auf ein Ding.
So ähnlich war auch meine Überlegung, warum ich kein Interface dafür wollte.
Decimad schrieb:
Hier finde ich das aber auch als Member besser, weil das Objekt ja zwar eine Position hat, aber nicht eine Position ist. Es wäre in deinem Fall also sozusagen eine bloße Abkürzung der Schreibweise, die du durch die Ableitung bezweckst.
Das Objekt ist keine Position, richtig. Aber es ist ein positionierbares Objekt (entsprechend dem Namen der Klasse). Wenn man nur einen Member hat, muss man die Positions-Zugriffsfunktionen jedes Mal duplizieren und kann auch nicht nur auf die Positions-Eigenschaft in der Basisklasse zugreifen. Die Vererbung scheint mir nicht grundsätzlich falsch zu sein, aber ich muss irgendwie alles richtig zusammensetzen.
Zum sonstigen Design: Genau, schau dir meinen letzten Post an
-
Ansonsten, denk auch an unsere "Properties" von drüben... Mach ne Positionable-Schnittstelle für den Quellcode, in deinem Objekt ein Attribut "position_" und dann noch ein Property "Position", dann kann man als Leveldesigner die Position mit irgendwas anderem verdrahten, das Positionen generiert.
Wenn ich mich bei OpenSceneGraph recht entsinne, dann sind Transformationen (Und als solche lassen sich ja Positionen widerspiegeln) eine eigene Klasse von Objekten... Sie sind nicht Teil des Scene-Nodes, der ein renderbares Objekt darstellt.
-
Den SceneGraph verschiebe ich wahrscheinlich auf später, wenn der Rest sauber durchdacht ist. Falls dann wieder Fragen auftreten, melde ich mich in diesem Thread.
Ich habe jetzt jedenfalls die Partikelklasse "data-driven" gemacht, also mit öffentlichen Membervariablen. Zugriff darauf ist hauptsächlich in den Emittern und Affektoren notwendig.