In the following piece of code (A java version of the original wikipedia example), you can see that, although an ExplodingAsteroid collidedWith a GiantSpaceShip, the output shows only a SpaceShip.
This is due to the fact that, though Java can recognize the runtime type of the Asteroid, it ignores the runtime type of the SpaceShip which is sent as an argument.
class SpaceShip {}
class GiantSpaceShip extends SpaceShip {}
class Asteroid {
public void collideWith(SpaceShip sp) {
System.out.println("Asteroid hit a SpaceShip");
}
public void collideWith(GiantSpaceShip gsp) {
System.out.println("Asteroid hit a GiantSpaceShip");
}
}
class ExplodingAsteroid extends Asteroid {
public void collideWith(SpaceShip sp) {
System.out.println("ExplodingAsteroid hit a SpaceShip");
}
public void collideWith(GiantSpaceShip gsp) {
System.out.println("ExplodingAsteroid hit a GiantSpaceShip");
}
}
public class DoubleDispatchTest { public static void main(String args[]) {
Asteroid ast = new Asteroid();
Asteroid ast1 = new ExplodingAsteroid();
SpaceShip sp = new SpaceShip();
SpaceShip sp1 = new GiantSpaceShip();
ast.collideWith(sp);
ast.collideWith(sp1);
ast1.collideWith(sp);
ast1.collideWith(sp1);
}
}
Output:
Asteroid hit a SpaceShip
Asteroid hit a SpaceShip
ExplodingAsteroid hit a SpaceShip
ExplodingAsteroid hit a SpaceShip
This problem can be solved by re-writing the above code as follows:
In this case, we are still using the runtime type of just one object with each call, but we have an additional call embedded within the called method, which invokes another of the second object (Asteroid), thus achieving double dispatch. The same effect can be achieved by using a couple of if-else statements within the code, but the code starts to look ugly once more types of spaceships/asteroids are introduced.
class SpaceShip {
public void collideWith(Asteroid inAsteroid) {
inAsteroid.collideWith(this);
}
}
class GiantSpaceShip extends SpaceShip {
public void collideWith(Asteroid inAsteroid) {
inAsteroid.collideWith(this);
}
}
class Asteroid {
public void collideWith(SpaceShip sp) {
System.out.println("Asteroid hit a SpaceShip");
}
public void collideWith(GiantSpaceShip gsp) {
System.out.println("Asteroid hit a GiantSpaceShip");
}
}
class ExplodingAsteroid extends Asteroid {
public void collideWith(SpaceShip sp) {
System.out.println("ExplodingAsteroid hit a SpaceShip");
}
public void collideWith(GiantSpaceShip gsp) {
System.out.println("ExplodingAsteroid hit a GiantSpaceShip");
}
}
public class DoubleDispatchJava {
public static void main(String args[]) {
Asteroid ast = new Asteroid();
Asteroid ast1 = new ExplodingAsteroid();
SpaceShip sp = new SpaceShip();
SpaceShip sp1 = new GiantSpaceShip();
sp.collideWith(ast);
sp.collideWith (ast1);
sp1.collideWith(ast);
sp1.collideWith(ast1);
}
}
Output:
Asteroid hit a SpaceShip
ExplodingAsteroid hit a SpaceShip
Asteroid hit a GiantSpaceShip
ExplodingAsteroid hit a GiantSpaceShip
And what about the case when SpaceShip collides with GiantSpaceShip?
ReplyDeletegood work!!
ReplyDeleteGood work!
ReplyDeletethanks a ton
ReplyDelete