如何删除instanceof以调用正确的方法?

时间:2011-11-02 17:00:18

标签: java

我有以下类的层次结构:

public interface Message
public interface V2Message extends Message
public interface V3Message extends Message

我定义了另一个接口来验证消息。

public interface Validation {
  boolean validate(Message message);
}

每个实现Validation的类都可以处理V2和/或V3消息,因此在我的实现中,我必须区分我想要验证的消息类型,因为代码会有所不同。

public class MyValidation implements Validation {
  public boolean validate(Message message) {
    if(message instanceof V2Message) {
      return validateV2((V2Message)message);
    } else if (message instanceof V3Message) {
      return validateV3((V3Message)message);
    }
}

我想知道是否有办法取消使用instanceof

4 个答案:

答案 0 :(得分:4)

一种方法是实施Visitor pattern。定义MessageVisitor接口:

public interface MessageVisitor {
  boolean visit(V2Message message);
  boolean visit(V3Message message);
}

然后重新定义Message接口以包含方法:

public void visitMessage(MessageVisitor visitor);

然后,每个具体的Message类都将实现visitMessage方法,如下所示:

public void visitMessage(MessageVisitor visitor) {
    visitor.visit(this);
}

由于这是在每个具体子类中定义的,因此编译器将调用visit的正确版本。

如果您需要的只是验证,这可能会有点过分。但是,如果您要实现其他需要以不同方式处理不同类型消息的操作,那么它的优势在于您可以在不更改消息类的情况下实现每个消息。本文开头的文章链接中描述了优缺点。

答案 1 :(得分:2)

你可以给Validate两种方法而不是一种方法:

public interface Validation {
  boolean validate(V2Message message);
  boolean validate(V3Message message);
}

这也会阻止传递一个简单的Message作为运行时错误。这也是一个更准确的API,因为您已经说过Validation实施无法处理Message,只能处理V2MessageV3Message

答案 2 :(得分:2)

public interface Message{
   boolean validate();
}

实施Message的具体课程将负责了解他们被问到validate()的时间。

答案 3 :(得分:0)

这让我觉得相当紧密,需要有关类/接口内部工作的知识才能“验证”它。如果可能,您应该使Message接口有自己的验证。

这会产生这样的结果:

public interface Message{
   boolean validate();
   // Stüfe
}

但是,它可能会在如何验证之间存在根本性的差异。 (已知在观察者模式中发生类似情况)。在这种情况下,我可能会使用重载来区分。

public interface Validation {
  boolean validate(V2Message message);
  boolean validate(V3Message message);
  boolean validate(Message message); // may not be needed, but in case you want 
                                     // still handle generic Messages, you will
                                     // definitely need it.
  // Stüfe
}

如上所述,这可能会带来更多编译时错误。除了您已经获得的内容之外,它不会提供任何实质性的反馈 - 您的代码将导致与传递通用Message相同的错误。