【发布时间】:2017-01-19 08:24:58
【问题描述】:
我们的 Java 应用程序在后端使用 Google Guava EventBus 进行通信。其中一些事件使用 Jersey 的 server-sent events support 发送到客户端以启用通知。客户端只对某些类型的事件感兴趣,这些事件以 JSON 格式发送到客户端。
目前我们正在使用if-else 和instanceof 以一种巨大的方法处理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;
} ...
}
当越来越多的事件添加到系统中时,这段代码开始变得混乱。经过一番研究,有一些替代方案,但还不够好。
1) 反思。
使用反射意味着我们可以使用声明的方式从事件对象中检索数据,而无需知道确切的类型。但是使用反射不是类型安全的,并且在处理嵌套路径时可能会很混乱,例如a.b.c.
2) 多态性
多态性看起来是instanceof 的一个很好的替代方案,但在这种情况下确实有效。使用多态意味着将toJSON 之类的方法添加到UIEvent 接口。但这会恢复依赖流并将 UI 细节暴露给事件总线。
3) 包装类
我还在考虑使用事件包装类将 JSON 主体构建逻辑封装在单独的类中。然后在事件总线的handleEvent方法中,我可以得到事件对象的类型并使用命名约定找到封装类,然后构造封装类实例,调用toJson方法得到JSON体。
public class AWrapper {
public AWrapper(A a) {
}
public Object toJson() {
}
}
这是迄今为止我能想到的最合理的方法。
需要建议和想法。
【问题讨论】:
-
Polymorphism 是这里的标准模式。但是,如果可能的话,您应该尝试在事件中测试一个字段并打开它。
-
多态性也有我的投票权。但是在接口上使用
toJson之类的方法会锁定您使用 json。您可以考虑的另一个解决方案是添加一个返回一组通用数据属性(例如Map<String, Object>)的方法,然后您可以使用该方法将其序列化为 json。 -
像 Jackson 或 Gson 这样的现代库可以毫不费力地将 POJO 序列化为 JSON,因此您不需要特殊的方法。为什么不创建一个自定义注释来区分内部事件和需要广播给客户端的事件?然后,您将在
handleEvent()中使用反射来检查注释是否存在。 -
@markspace 我不想使用多态的原因是因为事件类在核心模块中,也被其他模块使用,但是对 JSON 逻辑的序列化在 API 模块中。我不想让核心模块知道 API 模块。
-
@MickMnemonic 发送到客户端的 JSON 正文有预定义的格式,所以简单的 JSON 序列化是不够的,需要进行数据转换。之前没考虑过自定义注解,看起来是区分不同事件的好选择。
标签: java json architecture software-design instanceof