在Java中避免'instanceof'

fns*_*nst 63 java oop instanceof

我有以下(可能是常见的)问题,现在绝对让我困惑:

有几个生成的事件对象扩展了抽象类Event,我想将它们分成Session Bean,比如

public void divideEvent(Event event) {
    if (event instanceof DocumentEvent) {
        documentGenerator.gerenateDocument(event);
    } else if (event instanceof MailEvent) {
        deliveryManager.deliverMail(event);
        ...
    }
    ...

}
Run Code Online (Sandbox Code Playgroud)

但是将来可能会有两种以上的事件类型,所以if-else将会很长并且可能无法读取.此外,我认为instanceof在这种情况下并不是真正的"最佳实践".

我可以在Event类型中添加一个抽象方法并让它们自行划分但是我必须在每个实体中注入特定的会话Bean.

是否有任何暗示可以为这个问题实现"漂亮"的解决方案?

谢谢你的帮助!

Pet*_*rey 54

最简单的方法是让Event提供一个可以调用的方法,以便Event知道该怎么做.

interface Event {
    public void onEvent(Context context);
}

class DocumentEvent implements Event {
    public void onEvent(Context context) {
         context.getDocumentGenerator().gerenateDocument(this);
    }
}

class MailEvent implements Event {
    public void onEvent(Context context) {
         context.getDeliveryManager().deliverMail(event);
    }
}


class Context {
    public void divideEvent(Event event) {
        event.onEvent(this);
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 你所展示的是**访客模式**的一个很好的例子. (11认同)
  • 我很担心这个.这似乎是将简单的POJO数据对象与逻辑混合在一起.事件不再成为数据包并开始成为其他方法的代表 (7认同)
  • @The Elite,它与访客模式类似,但不一样.访问者模式用于基于封闭对象图插入行为.IMO,这更接近标准的`ActionListener.actionPerformed`模式. (3认同)
  • 事件不会,但DocumentEvent可能知道要生成的文档.;)问题相当抽象,这种方法并不适用于所有情况,但如果它确实有效,它将是最简单,最容易扩展的解决方案. (2认同)

Cha*_*tin 11

多态性是你的朋友.

class DocumentGenerator {
   public void generate(DocumentEvent ev){}
   public void generate(MainEvent ev){}
   //... and so on
}
Run Code Online (Sandbox Code Playgroud)

然后就是

 DocumentGenerator dg = new DocumentGenerator();

 // ....
 dg.generate(event);
Run Code Online (Sandbox Code Playgroud)

更新

许多人提出反对意见,"你必须在编译时知道各种事件." 而且,是的,您显然必须知道您在生成器部件的编译时要解释的事件,否则您何时可以编写生成部件?

这些竞争示例使用Command模式,这很好,但意味着事件不仅要知道它们的表示细节,还要知道如何打印它们的表示.这意味着每个类可能有两种需求变化,它们的敏感性:事件所代表的变化,以及事件在打印中的表示方式的变化.

现在,考虑一下,例如,需要将其国际化.在命令模式的情况下,你必须去ñň不同的事件类型,并写入新的方法.在多态性的情况下,更改被本地化为一个类.

当然,如果您需要进行一次国际化,您可能需要多种语言,这会促使您在Command-pattern案例中为每个类添加类似策略的内容,现在需要n个类× m种语言; 再次,在多态性情况下,您只需要一个策略和一个类.

有理由选择任何一种方法,但声称多态方法是错误的只是不正确.

  • 这看起来很好看,但可能不合适,因为它需要在编译时知道类型,这在所讨论的情况下显然不是这种情况. (4认同)
  • 更具体地说,上面不会编译.`dg.generate(event)`调用将失败,因为在`DocumentGenerator`上没有匹配`generate(Event)`的方法.多态性不适用于像这样的方法参数. (4认同)

Geo*_*nis 8

每个事件都有一个功能,比如do.每个子类都覆盖do,以执行(:P)适当的操作.动态调度之后会执行其他所有操作.你需要做的就是调用event.do()