【问题标题】:Handling collections with mixed POJOS, with different handler for each POJO使用混合 POJO 处理集合,每个 POJO 使用不同的处理程序
【发布时间】:2010-10-20 19:06:22
【问题描述】:

我正在尝试为以下问题找到一个优雅的 OOP 解决方案。

假设我们有一个 POJO 集合,在这种情况下是事件,其中每个 POJO 可能是不同的类。我们需要处理这个集合,对每个 POJO 类(或类型)使用不同的规则。

一个基本假设是我们不能用适当的处理程序来装饰 POJO,因为我们不控制它们的生成,并且按原样接收集合。因此,任何对此的机制都落入了同一个陷阱。但是,第 3 项仍然处理这种可能性。

有一些可能的解决方案,一些非常丑陋,一些更优雅但复杂:

  1. 最明显的解决方案是使用 instanceOf 运算符将 POJO 传递给处理程序。
  2. 对 1 的稍好的修改是为此使用责任链,使用链式调度程序,以便新类型只需要一个新的调度程序。但是,每个调度程序仍然需要 instanceOf。
  3. 创建增强对象,而不是 POJOS,其中每个对象都包含对其处理程序的引用。这会在 POJO 和我们的处理器之间建立耦合。
  4. 创建(我知道如何在 Java 中正确执行此操作)一个调度程序服务,该服务将处理程序注册到特定事件类,并使用泛型(Typesafe 容器,如在有效的 java 中)将事件调度到处理程序。

4 是最优雅的,但我想知道是否有更好的想法。

【问题讨论】:

    标签: java language-agnostic design-patterns


    【解决方案1】:

    我在这个场景中使用了第 4 号的解决方案,我认为它是一个很好的解决方案。我也会寻求其他意见以更好的解决方案。

    【讨论】:

      【解决方案2】:

      4 是您提出的最佳解决方案。 #1 和 2 会因为 instanceof 的乱七八糟而痛苦。

      另一种解决方案:使用它的调度程序方法注释每个类。您不需要一个中心位置来处理调度程序调用,并且 POJO/调度程序不会在注释之外耦合。

      【讨论】:

      • 他可能无法注释它们,因为他不负责它们的创建,这也可能意味着它是第 3 方类。
      【解决方案3】:

      #4 的简化:

      使用 Map 来存储每个事件类的处理程序。

      Map<Class, Handler> classHandlers = new HashMap<Class, Handler>();
      classHandlers.put(EventA.class, new EventAHandler());
      classHandlers.put(EventB.class, new EventBHandler());
      

      现在使用事件的类来获取事件的处理程序。

      Handler handler = classHandlers.get(event.getClass());
      handler.handle(event);
      

      当然,这需要在编码时了解所有可能的事件类,因此不如外部事件调度器灵活。

      【讨论】:

      • 在编码时你总是会知道所有现有的事件类 :-) 每次添加新类时,都需要添加新的处理程序,然后开始编码......
      • +1。 “这需要在编码时了解所有可能的事件类”:对我来说,这似乎是基本要求的一部分。
      • 即使您不了解所有这些,您也可以创建一个默认处理程序,该处理程序只是将未处理的 POJO 类记录在某处。现在您知道自己缺少什么了。
      • 如果你有很多子类或不同的接口实现,这会变得非常混乱。
      • 当然,对于每个子类,您都需要一个 put() 方法调用,但“混乱”完全是另外一回事。 :)
      【解决方案4】:

      假设我们有一个 POJO 集合,在这种情况下是事件,其中每个 POJO 可能是不同的类。我们需要处理这个集合,对每个 POJO 类(或类型)使用不同的规则。

      恭喜如果 POJO 的类是稳定的(不经常添加新的类类型),您刚刚描述了使用访问者模式的动机!

      更好的是,因为您可能想要对您的 POJO 集合做不同的事情,您可以创建一个 AbstractBaseVisitor 并对其进行扩展以处理您需要做的不同事情!

      这需要在每个 POJO 周围放置一个小型包装器,每个 POJO 类有一个包装器类,以添加一个回调访问者的 visit() 函数。

      【讨论】:

      • 除非我遗漏了什么,否则这并不能解决问题。您需要一种机制来分配正确的包装器,这是同样的问题。
      【解决方案5】:

      这个问题实际上与语言无关。在某些语言中,您可以轻松地装饰类。但是,让我们坚持使用 Java。即使在那里我说“这取决于”。

      我们想做的一件显而易见的事情是对处理程序进行某种自动发现。例如,使用 @Handler(handles=PojoA.class) 注释来注释您的处理程序,然后扫描所有使用 @Handler 注释的类(基本上需要加载类文件的混乱方式或使用类似 Scannotation 的东西)。

      如果您在 Spring 等上下文中运行,则会出现一个更有趣的选项。可以获取所有实现某个接口的bean,如下:

      public interface Handler<T> {
          void handle(T object);
      }
      

      然后在您的调度程序代码中找到它们:

      Collection<Handler> handlers = applicationContext.getBeansofType(Handler.class).values();
      for (Handler handler : handlers) {
          Method handleMethod = handler.getClass().getMethod("handle", Object.class);
          Class<?> type = handleMethod.getParameterTypes()[0];
          register(type, handler);
      }
      

      (诚然,上面的代码未经测试)

      我意识到我已经超越了这里的界限。我的观点是,解决方案的优雅程度取决于您选择的语言、您愿意使用的外部工具以及您使用的框架。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-06-28
        • 2019-08-30
        • 2017-07-01
        • 1970-01-01
        • 2016-12-04
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多