I'm sure this has been answered 100 times but I'm not sure what to search for. I want to create an interface with an abstract method that enforces a parameter of self-type of the class that implements it.
Whew, that's a mouthful.
For example, I have an interface called Collider, with a method called isColliding. I have a class called Player that implements Collider. In my use case, only objects of the same sub-type of Collider will need to check if they're colliding with each other. I want Player to implement the method isColliding, but I want the function prototype to be enforced as isColliding(Player p), as opposed to isColliding(Collider c)
I've managed to implement what I'd consider a work-around, by declaring Collider as
public interface Collider<T extends Collider<T>> {
public abstract boolean isColliding(T other);
}
But when I declare my class that implements collider, the class prototype looks like this
public class Player implements Collider<Player>
This seems ugly and not necessarily as type-safe as I'd like. It seems like there should be a way to make that <Player> implied. My goal is to have the child class's Overridden function prototype look like this
public boolean isColliding(Player other)
Thanks in advance!
edit:
To give some more background:
I have a singleton class called Collision, which registers my objects that may collide with each other. Inside Collision I have a Hashmap declared as
HashMap<Class, ArrayList<Collider>> colliders
This is my data structure for storing the objects that may collide with each other. They are mapped by class, because my design only requires each class to check if it is colliding with itself. Collision has its own isColliding function to be called from within my objects that implement Collider. It looks like this
public <T extends Collider> boolean isColliding(T c) throws ColliderNotPopulatedException {
ArrayList<T> cList = (ArrayList<T>)colliders.get(c.getClass());
if (cList == null) {
throw new ColliderNotPopulatedException();
}
for (T otherC : cList) {
if (c != otherC && c.isColliding(otherC)) {
return true;
}
}
return false;
}
I'm getting NoSuchMethod errors as I try to call isColliding in this method, and I suspect it's because the self-typeness isn't implemented. Should I re-think my design? Are there patterns that would make this cleaner?
edit 2:
I managed to get past the error my casting 'otherC' as type (T) in the call to isColliding. It seems that this implementation will work for me. Thanks everyone for your help!
It seems like you are trying to create some kind of game or game engine, right? in this case I also guess that at some point you will like to detect collisions not only between Persons but also between other things (eg Person,Monster,Vehicle etc).
You possibly need to re-think your design a bit and not go into the self-types.
First I would suggest you to make all the objects that may collide subclasses of a common type which exposes the properties which you can use to detect collision (it may be position,polygon etc).
public interface GameObejct {
int getProperty1();
int getProperty2();
}
public class Person implements GameObejct {
@Override
public int getProperty1() {
return 0;
}
@Override
public int getProperty2() {
return 0;
}
}
public class Monster implements GameObejct{
@Override
public int getProperty1() {
return 0;
}
@Override
public int getProperty2() {
return 0;
}
}
The collision detection logic does not belong to the objects (Person,Monster etc) but on another part of the program.The object it self does not need to know that it can collide with something.
Since you expressed the desire to use different collision detection methods you can use a collision detection policy and create various instances which you can use.
public interface CollidingDetectionPolicy <T extends GameObejct> {
boolean objectsColliding(T object1,T object2);
}
public class SimpleCollisionDetector implements CollidingDetectionPolicy<GameObejct> {
@Override
public boolean objectsColliding(GameObejct object1, GameObejct object2) {
// detect collision using a simple method...
return false;
}
}
public class ComplexCollisionDetector implements CollidingDetectionPolicy<GameObejct> {
@Override
public boolean objectsColliding(GameObejct object1, GameObejct object2) {
// detect collision using some other more complex method
return false;
}
}
the main engine of your game should check for collisions when appropriate.
public class GameEngine {
public void detectCollisions() {
/// ...
/// ...
// need to know if there is some collision
// get all the objects on screen and the current collision detection policy (see note)
List<GameObejct> currentlyVisibleObjects = getObjectsOnScreen();
CollidingDetectionPolicy collisionDetector = getCollisionDetectionLogic();
// naive implementation . don't traverse your list this way!Think about complexity!
for (int i = 0; i < currentlyVisibleObjects.size() - 1; i++) {
GameObejct object1 = currentlyVisibleObjects.get(i);
for (int j = i + 1; j < currentlyVisibleObjects.size(); j++) {
GameObejct object2 = currentlyVisibleObjects.get(j);
if (collisionDetector.objectsColliding(object1, object2)) {
// object colliding ...do something
}
}
}
}
public List<GameObejct> getObjectsOnScreen () {
... // return the list of game objects
}
public CollidingDetectionPolicy getCollisionDetectionLogic() {
... /// return the detection implementation
}
}
NOTE: I don't find it wise the object itself to provide the detection policy because in the case 2 objects provide different policy the comparison semantics will be a bit weird as in the following case:
lets assume that the object itself could provide us its preferred detection policy using method
public CollidingDetectionPolicy getDetectionPolicy();
and we had to check these two objects
Person p = ...;
Monster m = ..;
then
p.getDetectionPolicy().objectsColliding(p, m)
could have different result than
m.getDetectionPolicy().objectsColliding(p, m)
which would be weird to say the least.