Reputation: 12328
I have read other related posts, but am still not quite sure how, or if it is possible to dynamically cast (interface to implementation) in Java. I am under the impression that I must use reflection to do so.
The particular project I am working on requires a usage of many instanceof
checks, and it is — in my opinion — getting a bit out of hand, so would appreciate any ideas/solutions.
Below is a mini example I wrote up just to clarify exactly what I'm wanting to do. Let me know if you need more information:
Interface:
public interface IRobot {
String getName();
}
Implementations:
public class RoboCop implements IRobot {
String name = this.getClass()+this.getClass().getName();
public RoboCop() {}
public String getName() { return name; }
}
public class T1000 implements IRobot {
String name = this.getClass()+this.getClass().getName();
public T1000() {}
public String getName() { return name; }
}
The class that handles the implementations:
import java.util.LinkedList;
import java.util.List;
public class RobotFactory {
public static void main(String[] args) {
new RobotFactory();
}
public RobotFactory() {
List<IRobot> robots = new LinkedList<IRobot>();
robots.add( new RoboCop() );
robots.add( new T1000() );
System.out.println("Test 1 - Do not cast, and call deploy(robot)");
for(IRobot robot : robots) {
deploy(robot); // deploy(Object robot) will be called for each..
}
System.out.println("Test 2 - use instanceof");
for(IRobot robot : robots) { // use instanceof, works but can get messy
if(robot instanceof RoboCop) {
deploy((RoboCop)robot);
}
if(robot instanceof T1000) {
deploy((T1000)robot);
}
}
System.out.println("Test 3 - dynamically cast using reflection?");
for(IRobot robot : robots) {
//deploy((<Dynamic cast based on robot's type>)robot); // <-- How to do this?
}
}
public void deploy(RoboCop robot) {
System.out.println("A RoboCop has been received... preparing for deployment.");
// preparing for deployment
}
public void deploy(T1000 robot) {
System.out.println("A T1000 has been received... preparing for deployment.");
// preparing for deployment
}
public void deploy(Object robot) {
System.out.println("An unknown robot has been received... Deactivating Robot");
// deactivate
}
}
Output:
[RoboCop@42e816, T1000@9304b1]
Test 1 - Do not cast, and call deploy(robot)
An unknown robot has been received... Deactivating Robot
An unknown robot has been received... Deactivating Robot
Test 2 - use instanceof
A RoboCop has been received... preparing for deployment.
A T1000 has been received... preparing for deployment.
Test 3 - dynamically cast using reflection?
So, to sum up my question, how can I completely avoid having to use instanceof
in this case. Thanks.
Upvotes: 10
Views: 10600
Reputation: 89169
Instead of using instanceof
you can use the Factory Method Pattern
Definition of Factory method...
Like other creational patterns, it deals with the problem of creating objects (products) without specifying the exact class of object that will be created.
You will need a RobotCreatorFactory
that will have a method called IRobot createRobot(String robotName) {...}
(seeing that your robot returns a name. My suggestions is that each robot will have a public static String name NAME = Robocop.class.getName();
. Inside the method you'll have a check such as
if (Robocop.NAME.equals(robotName) { return new RoboCop(); }
That way, you alleviate instanceof
. And also, you can use @Meriton's advice on a DeploymentVisitor
(using a visitor pattern)....
PS My example is a rough explanation of the Factory method pattern. An example exists in GoF book and Wikipedia.
Upvotes: 0
Reputation: 346307
Dispatch of overloaded methods is done statically at compiletime, so your approach cannot be made to work. It's also very bad design. Doesn't it strike you as peculiar that the getName()
method, the only thing that differs between the robot classes, is never actually called?
You have to ditch the overloaded methods, and instead use method overriding of methods in the robot classes, which you call directly. i.e.
public void deploy(IRobot robot) {
System.out.println("A "+robot.getName()+" has been received..."
+" preparing for deployment.");
// preparing for deployment
}
Upvotes: 3
Reputation: 19717
Kent Beck says in his book Test Driven Development: Any time you're using run-time type-checking, polymorphism should help. Put the deploy() method in your interface and call it. You'll be able to treat all of your robots transparently.
Forget Reflection, you're just over thinking it. Remember your basic Object Oriented principles.
Upvotes: 3
Reputation: 5559
You can avoid instanceof by moving the deploy method in your IRobot interface and implementations.
The explanation of the behavior is that your three deploy methods are three different methods; overloaded methods with different signatures. At compile time, it's determined which one is chosen, not at runtime based on the real class...
Upvotes: 2
Reputation: 70564
You can make deploy a method of IRobot
, or use the visitor pattern.
And no, reflection will not make things any easier here.
Upvotes: 7