Erweiterung von Klassenfamilien - Wie macht man das schön?



  • Hallo alle.

    Folgende Situation: Man möchte die Bewegung von Autos in einer Stadt und von Ameisen in ihrem Ameisenhaufen mittels des selben frameworks beschreiben.

    Es gibt offensichtliche Ähnlichkeiten, was das ganze überhaupt erst geeignet erscheinen lässt, um im selben framework zu laufen: man hat einzelne sich bewegende Objekte, es gibt ein zugrundelegendes Netzwerk von Orten und Straßen und es gibt gewisse Regeln, nach denen sich die Objekte bewegen.

    Ich habe das so implementiert, dass wenn ein TrafficParticipant (ein Auto/eine Ameise) an einem Knoten des Netzwerks ankommt, von einer Klasse namens TrafficAuthority entschieden wird, wohin er als nächstes geht. Der Speicher für die Einzelobjekte wird von einer Klasse verwaltet, weiterhin gibt es ein PriorityQueue System, das den zeitlichen Ablauf verwaltet, und weiteren Kram der aber im Prinzip unwichtig ist.

    Meine Frage ist folgende:
    Die Objekte kennen sich gegenseitig per Referenz, allerdings nur als Referenzen auf die jeweiligen Basisklassen. Wenn die konkrete Systemdynamik aber von Details abhängt, die nur eines der Systeme aufweist, kann Detailwissen über den wahren Typ der Referenzen nötig sein.

    Quick & dirty kann man das regeln, indem man den abgeleiteten Komponenten zusätzliche Referenzen auf die anderen abgeleiteten Komponenten mitgibt, oder indem man explizites typecasting benutzt wenn man auf diese zugreift, aber wie macht man das elegant? Habe ich meine Klassen einfach nur schlecht designt?

    Zusammenfassend könnte man von Vererbung von ganzen Systemen sprechen, die sich hinter facades verstecken; man möchte die abgeleiteten Systeme mittels des facade interfaces ansprechen, aber die Kopplung innerhalb der facade erfordert eine Bindung an konkrete abgeleitete Klassen.

    Danke schonmal für alle Antworten mit Tips und Vorschlägen!



  • Also für mich klingt das ganze recht starkt nach casting.

    Da wirst du nicht drum herum kommen, wenn du den genauen Typ haben willst.

    Kannst du mal vlt. ein kleines Beispiel zeigen, wie du genau meinst? (ein wenig Code).



  • Willst du von Auto und Ameise gleiche Methoden aufrufen, aber die sollen was anderes machen oder unterschiedliche Methoden? Erstes geht mit Polymorphie.



  • mir fällt kein guter name schrieb:

    Willst du von Auto und Ameise gleiche Methoden aufrufen, aber die sollen was anderes machen oder unterschiedliche Methoden? Erstes geht mit Polymorphie.

    So wie ich das verstehe sollen eben Methoden aufgerufen werden, die von Auto oder Ameise abhängen. (Also so ::AutoStarten oder so).



  • Ich würde das einfach in einen AutoDecider/AmeisenDecider auslager, der von einer methode zurückgegeben wird, und dan spezifisch für das objekt ist.
    Also Ameise::GetDecisionObject() -> AmeisenDecider und analog beim auto.



  • Ok, ich versuchs weiter zu konkretisieren.

    Mein Enduser-Interface das alles zusammenbindet, nennt sich 'simulation'. Eine Simulation besteht aus mehreren Komponenten:

    • Speicherverwaltung (für alle denkbaren Simulationen gleich)
    • Scheduler für zeitlichen Ablauf (ebenfalls gleich)
    • Netzwerk (Situationsspezifisch, ein Ameisenhaufen unterscheidet sich von einer Stadt)
    • TrafficAuthority ('KI' die entscheidet, wer wann wo langzulaufen hat: ebenfalls situationsspezifisch)
    • ...

    Der zeitliche Ablauf ist diskret, das heißt man hat keine Straßen auf denen sich Akteure langsam und kontinuierlich von einer Abzweigung zur nächsten bewegen, sondern man hat nur diskrete Zustandsänderungen, wenn etwas passiert ("event": ein Auto kommt in die Stadt, ein Auto erreicht Kreuzung xy). Wannimmer ein event passiert, bekommt die KI die Gelegenheit, in das Geschehen einzugreifen (Beispiele: Stau auf der A5 - weise Autos an, diesen Bereich zu umfahren, ein Taxi wird frei - schicke es zum nächsten wartenden Fahrgast).

    Speziell das Vorgehen der KI hängt natürlich total vom System ab (das ist denke ich der von 2FE4DDD8 vorgeschlagene "decider"). Wenn jetzt aber auch andere Komponenten vom genauen setup abhängen, zum Beispiel das Netzwerk hat eine Anzahl von Eingängen und Ausgängen wo Autos auftauchen und verschwinden, dann reicht es der KI nicht, eine Referenz auf ein generisches "Netzwerk" mit Knoten und Kanten zu haben, sondern für sinnvolle Entscheidungen ist die Kenntnis der Eingänge und Ausgänge auch relevant (je nach Zielsetzung der KI).

    Das bringt mich wie gesagt in die Situation dass entweder die konkrete KI die Netzwerkreferenz ihrer abstrakten Basisklasse auf eine XYZ-Netzwerk Referenz typecasten muss, oder ich muss zusätzliche Referenzen für die abgeleiteten Klassen einführen.

    Etwas unelegant, aber generell ist an dieser Stelle denke ich Vererbung angebracht, weil das minimale interface zwischen den Komponenten für alle Situationen gleich ist (insbesondere auch das externe interface für den User). Es geht mir jetzt nur darum, die jeweils zusätzlichen internen interfaces zwischen den Komponenten in den Griff zu kriegen.



  • Für die einzelnen Aktionen könnte man was mit Commands machen. Wikipedia: Command_Pattern



  • Ja, "events" stellen ein Command dar.


Anmelden zum Antworten