Java - 从接口到实现的动态类转换
我读过其他相关的文章,但我仍然不太确定如何,或者是否可以在 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
您可以部署
IRobot
的方法,或使用访问者模式 。不,反思不会让事情变得更容易。
You can make deploy a method of
IRobot
, or use the visitor pattern.And no, reflection will not make things any easier here.
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.
重载方法的分派是在编译时静态完成的,因此您的方法无法工作。这也是非常糟糕的设计。
getName()
方法是机器人类之间唯一不同的东西,但它实际上从未被调用,这难道不会让您感到奇怪吗? ?您必须放弃重载方法,而是使用直接调用的机器人类中方法的方法重写。 IE
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.
您可以通过在 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...
您可以使用 工厂方法模式,而不是使用
instanceof
工厂方法的定义...
您将需要一个
RobotCreatorFactory
,它有一个名为IRobot createRobot(String robotsName) {...}
的方法(看到您的机器人返回一个名称。我的建议是每个机器人将有一个public static String name NAME = Robocop.class.getName();
。在该方法中,您将进行诸如这样的检查,这样就可以减轻
instanceof
的负担。而且,您可以在 DeploymentVisitor 上使用 @Meriton 的建议(使用访问者模式)....PS 我的示例是对工厂方法模式的粗略解释。 GoF 书籍和维基百科中有一个例子。
Instead of using
instanceof
you can use the Factory Method PatternDefinition of Factory method...
You will need a
RobotCreatorFactory
that will have a method calledIRobot createRobot(String robotName) {...}
(seeing that your robot returns a name. My suggestions is that each robot will have apublic static String name NAME = Robocop.class.getName();
. Inside the method you'll have a check such asThat way, you alleviate
instanceof
. And also, you can use @Meriton's advice on aDeploymentVisitor
(using a visitor pattern)....PS My example is a rough explanation of the Factory method pattern. An example exists in GoF book and Wikipedia.