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

发布于 2024-09-26 13:28:41 字数 2778 浏览 2 评论 0原文

我读过其他相关的文章,但我仍然不太确定如何,或者是否可以在 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 。谢谢。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

拍不死你 2024-10-03 13:28:41

您可以部署IRobot的方法,或使用访问者模式

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

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

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

无声静候 2024-10-03 13:28:41

Kent Beck 在他的书中测试驱动开发中说:任何时候你使用运行时类型检查,多态性应该有所帮助。将deploy() 方法放入您的界面中并调用它。您将能够透明地对待所有机器人。

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

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.

傲影 2024-10-03 13:28:41

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

您必须放弃重载方法,而是使用直接调用的机器人类中方法的方法重写。 IE

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

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
}
愁以何悠 2024-10-03 13:28:41

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

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

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

离鸿 2024-10-03 13:28:41

您可以使用 工厂方法模式,而不是使用 instanceof

工厂方法的定义...

与其他创作模式一样,它
处理创建的问题
未指定的对象(产品)
对象的确切类别
创建。

您将需要一个 RobotCreatorFactory ,它有一个名为 IRobot createRobot(String robotsName) {...} 的方法(看到您的机器人返回一个名称。我的建议是每个机器人将有一个public static String name NAME = Robocop.class.getName();。在该方法中,您将进行诸如这样的检查

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

,这样就可以减轻instanceof的负担。而且,您可以在 DeploymentVisitor 上使用 @Meriton 的建议(使用访问者模式)....

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

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文