10

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.

4
  • 4
    +1 for the cool Robot example :-) Commented Oct 6, 2010 at 20:56
  • thanks, I tried to make it somewhat interesting to read hehe :) Commented Oct 6, 2010 at 21:04
  • 2
    More often than not having to use instanceof or cast implies a problem with your design. This isn't always true, but if it's happening a lot then It's almost guaranteed that there is a better design out there. In this case, why isn't deploy a method in robot--the system.out.println you use there should absolutely be inside robot. If deploy can't be a method in robot, then it should only call methods in the robot interface (so that you only need a single deploy method). Commented Oct 6, 2010 at 21:48
  • @Bill Yes I admit, in this example it's easy to see that now. I had to step back from the actual deployment code, which isn't as obvious (or at least to me it wasn't). Meriton's Vistor pattern is what I eventually resorted to and will apply. Commented Oct 6, 2010 at 21:56

5 Answers 5

7

You can make deploy a method of IRobot, or use the visitor pattern.

And no, reflection will not make things any easier here.

Sign up to request clarification or add additional context in comments.

4 Comments

Yes, that was my initial whim as well. I typically try to avoid Reflection if possible
Actually this is working quite nice in my demo. I will try it on the actual product code, which has quite a bit more degrees of complexity to it, and let you know how it goes. Thanks.
Excellent, you sir, just helped me delete 100's of lines of code!
And an additional note. My real-life code actually uses an Abstract Class So in that case do not fill in the body of the deploy() method in the Abstract class, but instead make it an abstract method and define it in each class that calls deploy (i.e. treat it like an interface)
3

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.

3 Comments

Right, I figured I was making it too complicated. Again, the idea of using reflection was a suggestion made to me.. though, i'm not a huge fan of it when it's not needed. :P
What really makes it tough is trying to modify existing code. Especially when it's code that has been worked on by many people for many years.. it becomes tougher to spot "the best thing to do" at the time
Absolutely. The best thing you can do then is to reverse engineer some diagrams, write some tests, and use automated refactoring tools (If you're using Java). It's usually pretty unpleasant, though.
3

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
}

4 Comments

thanks, everything made sense and the demo worked for me. Though I want to be sure that I fully understand what you meant by "method overriding of methods", you would say that thedeploy method is defined in the RobotFactory correct? and what changes should be made to the IRobot Impelementations? (other thant the getName method, I just slapped it in there for the demo)
@KennyCason: method overriding isn't the best word, since you're using an interface. What you want is dynamic dispatch. You get that when you have different classes that implement the same method (same name, same parameters) differently. When you call such a method, the implementation of the actual runtime class of the object on which you call it is used. If you use overriding (same name, different parameters), that does not happen, instead the compile time type of the reference determines which implementation is used.
ah. got it. That is an important distinction
"overriding (same name, different parameters)" - I assume you mean over_loading_?
2

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...

1 Comment

"At compile time, it's determined which one is chosen, not at runtime based on the real class" - thanks, I was not aware of that.
0

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.

2 Comments

Thanks, The problem isn't so much on the creation of the objects as it is how to design the code to "receive" the objects, of which adhere to an Interface, and properly handle the implementations.
Ah, late night on SO makes the brain slow. You can have public void deploy(IRobot robot) {System.out.println("A " + robot.getName() + " has been deployed."); }. Only on runtime will your jvm pass the concrete classes of IRobot. I totally misinterpreted your question.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.