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

Java—从接口到实现的动态类转换,java,reflection,dynamic,casting,Java,Reflection,Dynamic,Casting,我读过其他相关的文章,但仍然不太清楚如何,或者是否可以用Java动态转换(接口到实现)。我的印象是,我必须用反思来做到这一点 我正在从事的特定项目需要使用许多检查的实例,而且在我看来,这有点失控,因此我希望有任何想法/解决方案 下面是我写的一个小例子,只是为了明确我想要做什么。如果您需要更多信息,请告诉我: 接口: public interface IRobot { String getName(); } 实施: public class RoboCop implements IRob

我读过其他相关的文章,但仍然不太清楚如何,或者是否可以用Java动态转换(接口到实现)。我的印象是,我必须用反思来做到这一点

我正在从事的特定项目需要使用许多检查的
实例,而且在我看来,这有点失控,因此我希望有任何想法/解决方案

下面是我写的一个小例子,只是为了明确我想要做什么。如果您需要更多信息,请告诉我:

接口:

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
    }
}
处理实现的类:

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

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

您可以使用
IRobot
的方法进行部署,或者使用


不,反射不会让事情变得更简单。

您可以通过在IRobot接口和实现中移动部署方法来避免instanceof


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

Kent Beck在他的书中说:无论何时使用运行时类型检查,多态性都会有所帮助。将deploy()方法放在接口中并调用它。你将能够透明地对待你所有的机器人


忘记反思吧,你只是想得太多了。记住您的基本面向对象原则。

重载方法的分派是在编译时静态完成的,因此您的方法无法正常工作。这也是非常糟糕的设计。
getName()
方法是机器人类之间唯一不同的东西,它从未真正被调用,这难道不会让您感到奇怪吗

您必须放弃重载的方法,而是直接调用robot类中方法的方法重写。i、 e

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

您可以使用

工厂法的定义

像其他创造模式一样,它 处理创建的问题 未指定的对象(产品) 将显示的对象的确切类别 创造

您需要一个
RobotCreatorFactory
,该工厂将有一个名为
IRobot createRobot(String robotName){…}
(查看您的机器人返回一个名称。我的建议是,每个机器人将有一个
公共静态字符串名称=Robocop.class.getName();
。在该方法中,您将有一个检查,例如

if (Robocop.NAME.equals(robotName) { return new RoboCop(); }
这样,您可以减少
实例的
。此外,您还可以使用@Meriton对
部署访问者的建议(使用访问者模式)


PS我的示例是对工厂方法模式的粗略解释。GoF book和Wikipedia中有一个示例。

+1对于酷酷的机器人示例:-)谢谢,我试着让阅读hehe:)更有趣,因为不必使用instanceof或cast意味着您的设计有问题。这并不总是正确的,但如果这种情况经常发生,那么几乎可以保证会有更好的设计。在这种情况下,为什么不在robot中部署一个方法呢?在robot中使用的system.out.println应该绝对位于robot内部。如果deploy不能成为robot中的一个方法,那么它应该只调用robot接口中的方法(因此您只需要一个deploy方法)。@Bill Yes我承认,在这个示例中,现在很容易看到这一点。我不得不从实际的部署代码中退一步,这并没有那么明显(至少对我来说不是)。梅里顿的
Vistor模式
是我最终采用并将应用的模式。是的,这也是我最初的心血来潮。如果可能的话,我通常会尽量避免反射。实际上,这在我的演示中非常有效。我将在实际的产品代码上试用它,它的复杂程度要高一些,并让您知道它是如何运行的。谢谢。太好了,先生,你刚刚帮我删除了100行代码!还有一个附加说明。我的实际代码实际上使用了一个
抽象类
,因此在这种情况下,不要在抽象类中填充deploy()方法的主体,而是将其作为一个抽象方法,并在调用deploy的每个类中定义它(即将其视为一个接口)“在编译时,它决定选择哪一个,而不是在运行时基于实际类-谢谢,我没有意识到。对,我觉得我把事情弄得太复杂了。同样,使用反射的想法是向我提出的一个建议。。不过,当它不需要的时候,我并不是它的超级粉丝真正困难的是试图修改现有代码。特别是当它的代码已经被许多人研究了很多年。。现在发现“最好的事情”变得更难了。然后,您可以做的最好的事情是对一些图表进行反向工程,编写一些测试,并使用自动重构工具(如果您使用的是Java)。不过,这通常很不愉快。谢谢,一切都很有意义,而且演示对我来说很有效。虽然我想确保我完全理解您所说的“方法重写方法”的意思,但您会说Deploy方法是在机器人工厂中定义的,对吗?IRobot的推进应该做哪些改变?(除了getName方法之外,我只是为了演示而把它放进去了)@KennyCason:methodoverriding不是最好的词,因为您使用的是接口。您需要的是动态调度。当您有不同的类以不同的方式实现相同的方法(相同的名称、相同的参数)时,您就会得到这个结果。调用此类方法时,将使用调用该方法的对象的实际运行时类的实现。如果使用重写(相同的名称,不同的参数),则不会发生这种情况,而是使用编译时类型th