2012-04-09 7 views
9

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, z. B. 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, die berücksichtigt werden sollten, wenn Kollisionserkennungsalgorithmen ausgeführt werden. 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 World Klasse, die alle Entities verwaltet und hat Methoden, um die Uhr des Simulators voranzutreiben und die Welt zu teilen, um Kollisionserkennung effizienter zu machen.Was ist ein gutes Muster zum Speichern von Implementierungen einer Schnittstelle und Abrufen bestimmter Implementierungen?

Mein Problem beinhaltet Entity Subtypen von World. Ursprünglich hatte World gerade eine Karte von Entities durch ID verschlüsselt, und eine Field oder RigidBody zurückzuholen gäbe es Methoden, die die Entity aus der Karte herausholen und eine instanceof Prüfung plus eine Besetzung zum gewünschten Subtype tun würden. Ich bin mir bewusst, dass instanceof Nutzung ist jedoch verpönt, so dass ich einen anderen Ansatz versucht.

Derzeit habe ich separate Karten innerhalb World für jede Schnittstelle. Zum Beispiel gibt es eine Karte für Collidables sowie eine Karte für alle Entities. Die Methode addCollidable() fügt beiden Karten hinzu und getCollidable() ruft nur die Karte Collidable ab. Dies vermeidet instanceof, aber es scheint mir immer noch schlechtes Design. Wenn ich mir eine andere Schnittstelle ausdenke, um Entity zu erweitern, brauche ich eine andere Karte in World und entsprechende Methoden.

Ich fühle mich wie dieses Problem ist nicht schrecklich obskur, was wird typischerweise in dieser Situation getan?

EDIT

Ich glaube nicht, das Besucher-Muster hier arbeiten, wie Besucher Sie auf den konkreten Typ versenden können, und einige meiner Abrufmethoden benötigen Interface-Typen abzurufen. Zum Beispiel würde Visitor 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.

+2

Sie können etwas haben wie ' T getEntityFromMap (Clase clazz)', diese Methode entfernt die Notwendigkeit von 'Collidables' map, und Sie fragen nur nach' getEntityFromMap (Entity.class) ', um ein zu bekommen Entität in ihrem allgemeinsten Fall und .... –

Antwort

1

Hier, was Sie verwenden können, ist Besucher Muster, dieses Tutorial auf Besucher Muster verwenden Sie es gegen ein ähnliches Problem, das Sie haben. http://www.youtube.com/watch?v=KSEyIXnknoY

+0

Das ist nah an dem, was ich brauche, aber leider versendet Besucher auf konkreten Typen, und ich benötige die Fähigkeit, auf abstrakte/Interface-Typen sowie konkrete Typen zu versenden. – derefed

0

Es erscheint mir plausibel, dass Sie ein extra Feld für die Kollidablen 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 (meistens wegen des persönlichen Geschmacks), ist jedoch, List<Collidable> als Typ zu verwenden, weil für Ihre Bedürfnisse - durch alle für Kollisionsprüfungen iterierend - eine Liste ein schnellerer Ansatz ist.

+0

Die Frage, die ich hier haben würde ist, dass, wenn ein Objekt 'obj' implementiert' Collidable' zu ​​"World" hinzugefügt wird, wie wird 'World' sagen können, dass' obj' in die 'Liste ' ohne Verwendung gesetzt werden soll eine 'instanceof' Prüfung? – derefed

+0

Ich nehme an, Sie haben bereits etwas wie 'World.addEntity (Entity newEntity)' Fügen Sie einfach 'World.addEntity (Collidable newCollidable)' hinzu, implementieren Sie es entsprechend und lassen Sie javac den Rest erledigen. – KJP

1

Verwenden instanceof ist verpönt, weil es oft erscheint in Kontexten, in denen es auf unvollständige Kapselung deutet. Zum Beispiel wird instanceof manchmal verwendet, um zwischen verschiedenen Arten von Objekten zu unterscheiden und operiert dann abhängig von ihrem Typ auf ihnen.Ein sauberer Weg dies zu tun könnte sein, den Code in die entsprechenden Klassen der Objekte zu setzen und stattdessen polymorphism zu verwenden. Also, statt nie mit instanceof, fragen Sie sich lieber, ob Ihre aktuelle Verwendung von instanceof könnte legitime sein?

Mit anderen Worten: Ist es möglich, den Code, der vom Typ der Entität abhängt, in die entsprechende Entitätsklasse zu verschieben? (Natürlich, wenn Sie einen Abschluss erreichen dies dokumentiert werden sollen, wie die Dinge ändern können.)

BTW ich glaube, Sie können Sie leicht aktuelle Design verallgemeinern durch einen Map<Class,List<Entity>> verwenden, die Sie erlauben würde, Halten Sie Entity-Listen für eine beliebige Anzahl von Typen. Sie könnten auch ein Array Class[] types = {...} haben, das alle Typen enthält, die unterschieden werden müssen. Jetzt brauchen Sie nur einen einzigen instanceof Operator in einer for Schleife innerhalb Ihrer add/removeEntity(...) Methoden, die alle Typen durchlaufen würde, die unterschieden werden müssen, und fügt die Entität zu/von allen relevanten Listen hinzu.

Verwandte Themen