Java - 从接口到实现的动态类转换

时间:2010-10-06 20:48:42

标签: java reflection dynamic casting

我已阅读其他相关帖子,但仍不太确定如何,或者是否可以在Java中动态转换(实现接口)。我的印象是我必须使用反射这样做。

我正在处理的特定项目需要使用许多instanceof项检查,而且 - 在我看来 - 有点失控,所以会感激任何想法/解决方案。

下面是我写的一个小例子,只是为了澄清我想要做的事情。如果您需要更多信息,请与我们联系:

接口:

public interface IRobot {
    String getName();
}

实现:

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; }
}

处理实现的类:

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

输出:

[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?

所以,总结一下我的问题,在这种情况下,如何完全避免使用instanceof。感谢。

5 个答案:

答案 0 :(得分:7)

您可以部署IRobot的方法,或使用visitor pattern

不,反思不会让事情变得更容易。

答案 1 :(得分:3)

Kent Beck在他的书Test Driven Development中说:每次使用运行时类型检查时,多态都应该有所帮助。将deploy()方法放在您的界面中并调用它。您将能够透明地对待所有机器人。

忘记反思,你只是在思考它。记住你的基本面向对象原则。

答案 2 :(得分:3)

重载方法的调度是在编译时静态完成的,因此无法使您的方法起作用。这也是非常糟糕的设计。是不是因为getName()方法,机器人类之间不同的 事物从未实际上调用而特别打击你?

您必须抛弃重载的方法,而是使用方法重写机器人类中的方法,您可以直接调用这些方法。即。

public void deploy(IRobot robot) {
    System.out.println("A "+robot.getName()+" has been received..."
                        +" preparing for deployment.");
    // preparing for deployment
}

答案 3 :(得分:2)

您可以通过在IRobot界面和实现中移动deploy方法来避免instanceof。

行为的解释是你的三种部署方法是三种不同的方法;重载具有不同签名的方法。在编译时,它确定选择哪一个,而不是在运行时基于真实类......

答案 4 :(得分:0)

您可以使用Factory Method Pattern

,而不是使用instanceof

工厂方法的定义......

  

与其他创作模式一样,它   处理创造的问题   没有指定的对象(产品)   将要确切的对象类   创建

你需要一个名为RobotCreatorFactory的方法IRobot createRobot(String robotName) {...}(看到你的机器人返回一个名字。我的建议是每个机器人都有一个public static String name NAME = Robocop.class.getName();。你会有一张支票,如

if (Robocop.NAME.equals(robotName) { return new RoboCop(); }

这样,你减轻了instanceof。而且,您可以在DeploymentVisitor上使用@ Meriton的建议(使用访客模式)....

PS 我的例子是Factory方法模式的粗略解释。 GoF书和维基百科中有一个例子。