Java 设计中 if-else 和 instanceof 的替代方案

Ale*_*eng 5 java architecture json software-design instanceof

我们的 Java 应用程序在后端使用Google Guava EventBus进行通信。其中一些事件使用 Jersey 的服务器发送事件 支持发送到客户端以启用通知。客户端仅对某些类型的事件感兴趣,并且这些事件以 JSON 格式发送到客户端。

目前,我们正在使用if-elsewithinstanceof来处理巨型方法中的 JSON 正文生成。UIEvent只是一个用作过滤器的标记接口。

@Subscribe
public void handleEvent(final UIEvent event) {
  if (event instanceof A) {
    A a = (A) event;

  } else if (event instance B) {
    B b = (B) event;

  } ...
}
Run Code Online (Sandbox Code Playgroud)

当越来越多的事件添加到系统中时,这段代码开始变得混乱。经过一番研究,有一些替代方案,但还不够好。

1)反思。

使用反射意味着我们可以使用声明性方式从事件对象中检索数据,而无需知道确切的类型。但是使用反射不是类型安全的,并且在处理嵌套路径时可能会很混乱,例如a.b.c.

2)多态性

多态性看起来是一个很好的替代方案instanceof,但在这种情况下确实有效。使用多态性意味着toJSONUIEvent接口添加类似的方法。但这会恢复依赖流并将 UI 详细信息暴露给事件总线。

3)包装类

我还在考虑使用事件包装器类将 JSON 主体构建逻辑封装在单独的类中。然后在事件总线的handleEvent方法中,我可以获取事件对象的类型并使用命名约定找到包装类,然后构造包装类实例,调用toJson方法来获取 JSON 主体。

public class AWrapper {
   public AWrapper(A a) {

   }

   public Object toJson() {

   }
}
Run Code Online (Sandbox Code Playgroud)

这是迄今为止我能想到的最合理的做法。

需要建议和想法。

ale*_*xbt 1

我相信Google Guava EventBus是经过精确设计的,因此您不必使用许多 if-else-if 来定义此类方法:

有些人提出了一个用于 EventBus 监听器的通用 Handler 接口。这会遇到 Java 使用类型擦除的问题,更不用说可用性问题了。

...

由于擦除,任何单个类都不能使用不同的类型参数多次实现通用接口。这与传统的 Java 事件相比是一个巨大的倒退,即使 actionPerformed 和 keyPressed 不是非常有意义的名称,至少您可以实现这两种方法!

通过创建自己的标记,您正在重新创建他们试图避免的问题。

对我来说,这就是 Guava 建议的使用方式:

EventBus eventBus = new EventBus();
eventBus.register(new Object(){
    @Subscribe
    public void handleEvent(A a) {
        System.out.println("a");
    }
});

eventBus.register(new Object(){
    @Subscribe
    public void handleEvent(B b) {
        System.out.println("b");
    }
});

...

eventBus.post(new A());
eventBus.post(new B());
Run Code Online (Sandbox Code Playgroud)

每种事件类型一个处理程序方法。显然,订阅者不需要像本示例中那样处于匿名类中

其他例子

http://tomaszdziurko.pl/2012/01/google-guava-eventbus-easy-elegant-publisher-subscriber-cases/