Ich schreibe einen Simulator, der mehrere Schnittstellen hat, die alle simulierten Objekte implementieren. Die Schnittstelle Entity
verfügt über Methoden, die alle Objekte haben müssen, wie das Abrufen von IDs und das Vorrücken des Zeitschritts für den Status des Objekts. Collidable
erweitert Entity
und stellt alles mit Volumen und Position dar, das bei der Ausführung von Kollisionserkennungsalgorithmen berücksichtigt werden sollte. Field
erweitert Entity
und stellt alles dar, das einen Standort einem Wert zuordnet; Diese werden verwendet, um Dinge wie magnetische Felder zu modellieren, die die Welt durchdringen, aber kein Volumen oder physische Form haben. RigidBody
ist eine Klasse, die Collidable
implementiert und Starrkörperdynamikalgorithmen bereitstellt. Ich habe eine Klasse World
, die alle Entities
verwaltet und Methoden hat, um die Uhr des Simulators zu beschleunigen und die Welt zu partitionieren, um die Kollisionserkennung effizienter zu machen.
Mein Problem beinhaltet das Abrufen von Entity
Subtypen von World
. Ursprünglich hatte World
nur eine Karte von Entities
nach ID, und um eine Field
oder RigidBody
zu erhalten, gäbe es Methoden, die die Entity
aus der Karte holen und eine instanceof
Prüfung machen würden plus eine Besetzung auf den gewünschten Subtyp. Ich bin mir bewusst, dass instanceof
Verwendung jedoch verpönt ist, also habe ich einen anderen Ansatz versucht.
Momentan habe ich separate Karten innerhalb von World
für jede Schnittstelle. Zum Beispiel gibt es eine Karte für Collidables
sowie eine Karte für alle Entities
. Die addCollidable()
-Methode fügt beiden Maps hinzu und getCollidable()
ruft nur die Collidable
-Map ab. Dies vermeidet instanceof
, aber es scheint mir immer noch schlechtes Design zu sein. Wenn ich mir eine andere Schnittstelle ausdenke, um Entity
zu erweitern, brauche ich eine andere Karte in World
und die entsprechenden Methoden.
Ich habe das Gefühl, dass dieses Thema nicht so schrecklich unklar ist. Was wird typischerweise in dieser Situation gemacht?
BEARBEITEN
Ich glaube nicht, dass das Visitor-Muster hier funktionieren wird, da Visitor es Ihnen ermöglicht, den konkreten Typ zu versenden, und einige meiner Abrufmethoden Interfacetypen abrufen müssen. Visitor würde beispielsweise funktionieren, wenn World
nur Methoden zum Abrufen von RigidBodies
und anderen solchen konkreten Klassen benötigt, aber ich kann keine Methode erstellen, die alle Collidables
mit Visitor abruft.
Die Verwendung von instanceof
ist verpönt, weil oft in Kontexten erscheint, in denen es auf unvollständige Kapselung hinweist. Zum Beispiel wird instanceof
manchmal verwendet, um zwischen verschiedenen Arten von Objekten zu unterscheiden und bearbeitet sie dann abhängig von ihrem Typ. Ein sauberer Weg dies zu tun könnte sein, den Code in die entsprechenden Klassen der Objekte zu setzen und statt dessen Polymorphismus zu verwenden . Also, statt nie mit instanceof
, fragen Sie sich lieber, ob Ihre aktuelle Verwendung von instanceof
möglicherweise legitim ist?
Mit anderen Worten: Ist es möglich, den vom Typ der Entität abhängigen Code in die entsprechende Entitätsklasse zu verschieben? ( Natürlich, sobald Sie zu einem Ergebnis kommen, sollte dies dokumentiert werden, da sich die Dinge ändern können. )
BTW Ich denke, Sie können Ihr aktuelles Design einfach verallgemeinern , indem Sie eine Map<Class,List<Entity>>
verwenden, mit der Sie Entity-Listen für eine beliebige Anzahl von Typen beibehalten können. Sie könnten auch ein Array Class[] types = {...}
haben, das alle Typen enthält, die unterschieden werden müssen.
Jetzt benötigen Sie nur einen einzigen Operator instanceof
in einer for
-Schleife innerhalb Ihrer add/removeEntity(...)
-Methoden, der alle Typen, die unterschieden werden müssen, durchläuft und die Entität zu allen relevanten Listen hinzufügt / entfernt.
Es erscheint mir plausibel, dass Sie ein extra Feld für die kollidierbaren Objekte in Ihrer Weltklasse verwenden, da es sich um eine spezielle Teilmenge von Daten handelt, die eine spezielle Behandlung erfordern.
Die einzige Sache, die ich ändern würde (hauptsächlich wegen des persönlichen Geschmacks), ist List<Collidable>
als Typ zu verwenden, weil für Ihre Bedürfnisse - durch alle von ihnen für Kollisionsprüfungen - eine Liste ist ein schneller & amp; leichter Ansatz.
Tags und Links java interface simulation subclass