Registriert: Do Sep 02, 2004 19:42 Beiträge: 4158
Programmiersprache: FreePascal, C++
Hallo allerseits
Nun prügel ich mich gedanklich gerade wieder mit einem Design-Problem herum. Und zwar habe ich ja einen haufen Klassen, die auch untereinander vererben.
Grob kann man einen Auszug dieser Klassenstruktur so beschreiben:
Object -> Buildable -> Upgradable -> Building
Object -> Buildable -> Unit
Also: von Buildable leiten zwei dinge ab (Upgradable und Unit), wobei von Upgradable wiederum eines ableitet. Nun haben alle diese Klassen Methoden bzw Aktionen, die in Controller verpackt werden sollen. Diese sind aber für Client und Server in einigen Punkten unterschiedlich. Beispielsweise muss der Server immer noch Clienten über die Aktion informieren usw. usf.. Weiterhin gibt es aber natürlich wiederum Gleichheiten zwischen beiden. Mein Problem ist jetzt, dass ich irgendwie in dem serverseitigen Controller für Building sowohl an die allgemeine Implementation des Upgradable-Controllers als auch an die Server-Implementation von Upgradable rankommen muss [Siehe Anhang für Veranschaulichung]... Als Inherited versteht sich. Das geht in Pascal nicht und das weiss ich auch. Man kann es hierbei auch nicht mit Interfaces lösen, schließlich brauche ich ja die Implementation, nicht die Definition.
Nun habe ich ein paar Ideen, wie ich das umgehen kann und mich würde interessieren, was ihr dazu denkt.
1. Ansatz Mit nicht-virtuellen Methoden und vielen Casts so etwas wie Mehrfachvererbung simulieren. Das würde dann bedeuten, dass ich sozusagen beim Aufruf der Methode "zwischen den Klassen hin und her springe". Ist sicherlich nicht die feine Englische Art, aber es müsste theoretisch funktionieren.
Problem welches ich hier sehe: Beim Springen aus der allgemeinen Klasse zu dem Server/Client-Pendant müsste man irgendwie wissen, ob es sich hier gerade um Server oder Client handelt...... Gut, wahrscheinlich würde es da ein einfaches if Self is TworldControllerServer tun. Macht das ganze zwar noch unangenehmer, aber was solls.
2. Ansatz Die Funktionalitäten, die Server/Clientspezifisch sind in eine externe Umgebung auslagern und damit irgendwie das ganze abfangen... Events und sowas, und zwar viel davon. Dann würde das ganze etwas dynamischer ablaufen.
Problem ist hier nur, dass ich diese ganzen Klassen mit Events überhäufen müsste, um diese ganzen "Injektionsmarken" zu setzen. Die Abfragen die dabei dazukommen... Hmm...
3. Ansatz Beim FPC-Team anfragen, ob die lust haben, Mehrfachvererbung zu implementieren *hust*.
Problem was ich hierbei sehe: Die werden das wohl kaum machen .
Habt ihr noch vorschläge, was man besser machen kann oder einen komplett anderen Ansatz? Ach, nur so nebenbei: Umstieg auf C++ ist für mich keine Lösung - Es ginge zwar, ich kann auch C++ (ein bisschen zumindest), aber ich will nicht.
*gespannt sei*
Gruß Lord Horazont
Du hast keine ausreichende Berechtigung, um die Dateianhänge dieses Beitrags anzusehen.
_________________ If you find any deadlinks, please send me a notification – Wenn du tote Links findest, sende mir eine Benachrichtigung. current projects: ManiacLab; aioxmpp zombofant network • my photostream „Writing code is like writing poetry“ - source unknown
„Give a man a fish, and you feed him for a day. Teach a man to fish and you feed him for a lifetime. “ ~ A Chinese Proverb
Registriert: Do Sep 02, 2004 19:42 Beiträge: 4158
Programmiersprache: FreePascal, C++
Interfaces definieren nur die Schnittstelle - das hilft mir aber rein garnicht. Die Ändert sich ja nicht, denn die wird schon in TworldController* definiert, also nicht in Client/Server. Es geht aber um den Inhalt der Methoden, die dort schon deklariert werden. Und der wandert bei Interfaces bekanntlich nicht mit.
Gruß Lord Horazont
_________________ If you find any deadlinks, please send me a notification – Wenn du tote Links findest, sende mir eine Benachrichtigung. current projects: ManiacLab; aioxmpp zombofant network • my photostream „Writing code is like writing poetry“ - source unknown
„Give a man a fish, and you feed him for a day. Teach a man to fish and you feed him for a lifetime. “ ~ A Chinese Proverb
Registriert: Di Okt 03, 2006 14:07 Beiträge: 1277 Wohnort: Wien
Also, wenn ich Dein Problem zusammenfassen darf: Du brauchst in der Baumhierarchie irgendwo Methoden, die weiter oben im Vererbungsbaum in eine andere Richtung abgezweigt sind, ist das so richtig?
Ich hatte das in dem Projekt, das ich gerade von Delphi nach Lazarus portiere auch so. Bei mir heißen die Dinger Module und sitzen auf einer Map (es ist eine kleine Tile-Engine) und decken dort das ganze Spektrum ab, was man in so einer Tile-Engine braucht: angefangen vom NPC bis über Ereignis-Trigger und Dinger, die das Skript oder auch weitere Maps aufrufen können ist alles vertreten. Bei so einem Sammelsurium kommt es vor, dass zwei Module, die in der Vererbungslinie ziemlich weit voneinander entfernt sind, gleiche Dinge machen müssen.
Ich habe das so gelöst: ich habe das Plug-In Objekt erfunden (keine Ahnung ob es das anderswo schon gibt): ein Objekt, das bestimmte Methoden hat, und in verschiedene andere Objekte "eingestöpselt" werden kann. Funktioniert hervorragend. Sieh es so: ein Objekt ist ein Flieger oder aber er hat die Fähigkeit, fliegen zu können; das kann jetzt eine Fliege sein oder auch ein Vogel. Diese Fähigkeit könnte man aus dem Objekt herauslösen und als eigenes Plug-In-Objekt verwalten, durchaus auch mit eigener Hierarchie. Ist auch so etwas wie Mehrfach-Vererbung. Man kann ja sogar ein Property draus machen.
Eine gute Dokumentation - als Selbstschutzmaßnahme - ist allerdings empfehlenswert.
Viele Grüße
Traude
Registriert: Do Sep 02, 2004 19:42 Beiträge: 4158
Programmiersprache: FreePascal, C++
Hm, das ist ja sowas wie Interfaces - nur 1. nicht auf Kompilerebene und 2. mit Implementation dran. Das wäre dann Ansatz nummer 4.... Okay, danke auf jeden Fall für diesen Hinweis. Jaaaaaaa... Ich glaube, das ist garnicht so schlecht. Dann hätte ich auf jeder Vererbungsebene des Hauptstammes zwei Plugin-Klassen, einmal Client und einmal Server, die die gleiche Schnittstelle wie die Hauptklasse haben. Dann kann ich immer ein Plugin zuweisen (pro Vererbungsebene) dessen Methoden dann aufgerufen werden. Besser als nen Stapel Events, den ich jedes mal Prüfen muss.
Inwiefern die Plugin-Klassen unter sich wiederum vererben, wird sich dann zeigen. Mit nicht-virtuellen Methoden und so wird das denke ich ganz gut laufen... Ich werd gleich mal ein bisschen rumspielen
Gruß Lord Horazont
_________________ If you find any deadlinks, please send me a notification – Wenn du tote Links findest, sende mir eine Benachrichtigung. current projects: ManiacLab; aioxmpp zombofant network • my photostream „Writing code is like writing poetry“ - source unknown
„Give a man a fish, and you feed him for a day. Teach a man to fish and you feed him for a lifetime. “ ~ A Chinese Proverb
Registriert: Do Sep 02, 2004 19:42 Beiträge: 4158
Programmiersprache: FreePascal, C++
Traude, du bist genial .
Du hast die optimale Lösung gebracht. Ich habe das ganze jetzt noch mit Interfaces kombiniert und es tut jetzt einwandfrei seinen Dienst. Dann kann ich morgen damit anfangen, das ganze auf mein Controller-Prinzip auszuweiten. Für euch skizziere ich hier jetzt mal den Aufbau, den ich verfolge.
Ich habe jetzt eine Reihe von Klassen namens TMainX (X = natürliche Zahl, die die Vererbungstiefe angibt, nur fürs Beispiel), die die Hauptvererbungskette bilden. Dann habe ich Interfaces, IMainXPlugin (X, wie oben). Die Interfaces erben immer auch von der vorherigen Schicht Nun kommen die Plugins dazu. Diese sind TMainXPluginY (X, wie oben, Y = Buchstabe, der das Plugin identifiziert, z.b. S für Server oder C für Client, was auch immer) benannt, erben von dem Plugin der vorherigen Schicht und implementieren das Interface der aktuellen Schicht. Dies geschieht immer über nicht-virtuelle Methoden. Warum das? Um dann in der Hauptklasse immer genau die Methode der aktuellen Ebene aufrufen zu können. Sozusagen Interleaved. Ich habe Beispielcode angehangen, mit dem ich das gerade ausprobiert habe. Es funktioniert wirklich wunderbar. Wenn ich jetzt zwei Vererbungschichten habe und eine Methode Test, um die sich jetzt mal alles dreht, sieht die Aufrufreihenfolge so aus:
TMain2.Test
TMain2PluginA.Test
TMain1.Test
TMain1PluginA.Test
Ob das Plugin vor oder nach dem Hauptcode abgearbeitet wird, kann man einfach entscheiden indem man den Aufruf an einer anderen Position setzt. Wie auch sonst .
Die Pluginklasse übergebe ich übrigens der Hauptklasse im Konstruktor. Da wird sie gleich auf ihre Interfaces überprüft, instanziiert und danach "auseinandergerupft" (GetInterface).
Der beste Vorteil ist halt, dass man, dadurch, dass die Methoden in den Pluginklassen nicht über virtual/override arbeiten, die einzelnen Schichten durch die Interfaces auch wirklich abfragen und einzeln aufrufen kann. Das ist das, was ich gesucht habe.
Gruß Lord Horazont
It's a kind of magic
Du hast keine ausreichende Berechtigung, um die Dateianhänge dieses Beitrags anzusehen.
_________________ If you find any deadlinks, please send me a notification – Wenn du tote Links findest, sende mir eine Benachrichtigung. current projects: ManiacLab; aioxmpp zombofant network • my photostream „Writing code is like writing poetry“ - source unknown
„Give a man a fish, and you feed him for a day. Teach a man to fish and you feed him for a lifetime. “ ~ A Chinese Proverb
Registriert: Di Okt 03, 2006 14:07 Beiträge: 1277 Wohnort: Wien
@Lord Horazont: danke für die Blumen.
@Flash: Ich habe einen Blick drauf geworfen. Du hältst Dich aber an die strenge Vererbungshierarche, oder? Die Plugin-Objekte sind aber etwas anderes: sie sind so etwas wie eine "Kontaminierung" von normalen Ojekten, also "greedy code". Es ist eigentlich nur ein Notnagel, um zu vermeiden ein und dieselbe Methode zweimal schreiben zu müssen, nur weil die Pascal Vererbungshierchie so unnachgiebig ist.
Kennt Ihr das Spiel Spore? Da setzt man Geschöpfe zusammen, das ist praktisch Mehrfachvererbung zum Quadrat. Man hat z.B. die Objekte "Vierbeinigkeit", "Flugfähigkeit", "Guter Geruchssinn", "Intelligenz", "Scharfsichtigkeit","Bepelzte Haut", "Balzverhalten" und so weiter. Und aus diesen Dingen setzt man ein Objekt zusammen. Daraus ergeben sich ungeheure Möglichkeiten. Das Objekt selber besteht nur aus Sub-Objekten. In das Sub-Objekt "Haut" stecke ich "bepelzte Haut", könnte aber auch "Federn" benutzen. Und das Sub-Objekt "Haut" könnte seinen eigenen Shader mitbringen (!). So etwas lässt sich sich auch in Pascal machen, obwohl es dort keine Mehrfachvererbung gibt.
Es wäre allerdings spannend, wie der Code für das SubObjekt "Intelligenz" aussieht.
Mitglieder in diesem Forum: 0 Mitglieder und 7 Gäste
Du darfst keine neuen Themen in diesem Forum erstellen. Du darfst keine Antworten zu Themen in diesem Forum erstellen. Du darfst deine Beiträge in diesem Forum nicht ändern. Du darfst deine Beiträge in diesem Forum nicht löschen. Du darfst keine Dateianhänge in diesem Forum erstellen.