Kenny Cason
Kenny Cason

Reputation: 12328

Java - Dynamic Class Casting from Interface to Implementation

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

Answers (5)

Buhake Sindi
Buhake Sindi

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

Michael Borgwardt
Michael Borgwardt

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

Mike
Mike

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

ivy
ivy

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

meriton
meriton

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

Related Questions