2016-05-03 7 views
1

Ich habe eine Entity Schnittstelle, deren Implementierungen miteinander kollidieren können. Ich möchte eine CollisionListener hinzufügen, die aufgerufen wird, wenn die Kollision stattfindet, die eine CollisionEvent akzeptiert, die die zwei kollidierenden Entitäten enthält. Gibt es eine Möglichkeit, dies ohne eine zyklische Abhängigkeit zwischen Entity und CollisionListener zu tun?Wie kann ich diese zyklische Klassenabhängigkeit entfernen?

Was ich zur Zeit:

public interface Entity { 

    void addCollisionListener(CollisionListener listener); 

    void getStrength(); 

    void dealDamage(); 

    void die(); 

    // Other methods 
} 

// To be implemented and added to Entities when you want to watch for collisions 
public interface CollisionListener { 
    void onCollision(CollisionEvent event); 
} 

public class CollisionEvent { 
    private final Entity source, collider; 

    public CollisionEvent(Entity source, Entity collider) { 
     this.source = source; 
     this.collider = collider; 
    } 

    public Entity getSource() { return source; } 

    public Entity getCollider() { return collider; } 
} 

Dies hat folgende zyklische Abhängigkeit:

Entity -> CollisionListener -> CollisionEvent -> Entity

Ich bin nicht sicher, wie dieses Problem zu lösen (oder wenn es sogar aufgelöst werden) weil Implementierungen der Schnittstelle CollisionListener Zugriff auf die von der Kollision betroffenen Objekte Entity haben sollen, damit sie auf sie reagieren können (z. B. durch Aufrufen der dealDamage oder die Methoden.

Ich weiß, dass es nichts streng falsch mit einer zyklischen Abhängigkeit (d. H. Der Code kompiliert und läuft gut), aber ich würde sie lieber vermeiden, wenn überhaupt möglich.

+1

Was ist das Problem hier? Java hat keine Probleme mit Klassen, die voneinander abhängen. Müssen Sie die Klassen in separaten Bibliotheken/Projekten aufbewahren? –

+2

Sie haben Entitäten, die auf kollidierende Entitäten warten. Dies wird inhärent eine bidirektionale Abhängigkeit sein. Sie können dies umgehen (wenn Sie das wirklich wollen), indem Sie eine externe Ressource (wie einen 'CollisionHandler') verwenden, die Kollisionen zwischen Entitäten behandelt, und dann müssen die Entitäten nicht über den' CollisionListener' Bescheid wissen (IE: you can Entferne die 'addCollisionListener()' Methode von 'Entity'). – Ironcache

+0

Es gibt nichts * falsch * genau mit den beiden Klassen, die voneinander abhängen, aber ich habe immer verstanden, dass dieses Szenario die Klassen zerbrechlicher und enger koppelt, was ich gerne vermeiden würde. –

Antwort

2

Haben Entity und CollisionListener über einander kennen ist nicht wirklich eine große Sache; die zyklischen Abhängigkeiten bedeuten, dass die beiden Klassen voneinander wissen (was sinnvoll ist; es ist ein zusammenhängendes System). Jedoch sind die beiden nicht fest miteinander verbunden, da sie sehr wenig über externe Implementierungsdetails wissen.

Um dies konkret zu machen, überlegen Sie, ob Sie einen Komponententest für eine Implementierung von Entity entwerfen sollten. Sie könnten sehr leicht CollisionListener (mit einer Ressource wie Mockito, oder sogar nur eine Implementierung im Komponententest, wie MockCollisionListener) zum Schein machen. Entity Implementierungen hängen nicht von externen Implementierungsdetails ab, und daher können Implementierungen frei geändert werden, solange die vertragliche Schnittstelle (CollisionListener) befolgt wird. Wenn Sie jedoch immer noch nicht möchten, dass Ihre Ressourcen voneinander wissen, sollten Sie die Mediator pattern in Betracht ziehen, die im Grunde nur besagt, dass Sie nicht über Ressourcen verfügen, die miteinander kommunizieren, sondern über Mediatorobjekte, die über sie verfügen Kommunikation zwischen ihnen.