【问题标题】:Avoid Visitor pattern with Guava or other lib?避免使用 Guava 或其他库的访客模式?
【发布时间】:2016-05-13 16:30:08
【问题描述】:

在某些情况下,访问者模式会产生不必要的复杂性和样板(许多接受方法),并且在我看来完全概括是不可能的(accept() 方法也返回值)。所以我认为在我的情况下是另一种解决方案。

我当然不想创建很多 if-else instanceof 块,我想找到一种聪明的方法来匹配特定类型(例如在列表中)与方法

例如 guava 在其EventBus 中具有类似的功能,可以将特定类型的事件与@Subscribe 注释的方法进行匹配,因此我正在寻找一个类似的库,以便在一般方式。


这是一个例子,我想要类似的东西:

神奇的界面:

/**  @param <R> - return type  * @param <I> - element super type */
public interface MagicDoubleDispatch<R, I>{
    R dispatch(I element);
}

我的“访客”实现(应该自动调用正确的方法)

public class EventFormatter extends MagicDoubleDispatchImpl<String, Event> {
    private String format(AddedEmployeeEvent event) {
        return String.format("Added new employee: %s with id %s", event.name, event.employeeId);
    }
    private String format(DeletedEmployeeEvent event) {
        return String.format("Deleted employee:(%s) %s (this can't be undone!)", event.employeeId, event.name);
    }
    private String format(AddedTimeCardEvent event) {
        return String.format("Timecard of %s has been added to %s", event.date, event.employeeName);
    }
}

我想要这个作为一个库(例如):

public abstract class MagicDoubleDispatchImpl<R, I> implements MagicDoubleDispatch<R, I> {
    //I want this ... probably using reflection as EventBus, I don't care..
}

客户端代码:

private EventFormatter eventFormatter = new EventFormatter();

public List<String> toStringList(List<Event> events) {
    return events.stream()
        .map(it -> eventFormatter.dispatch(it))
        .collect(Collectors.toList());
}

【问题讨论】:

  • 为什么不用番石榴?
  • 出于同样的原因,我写了this。它旨在用作碰撞系统,但我认为它能够以更通用的方式使用。
  • Aglassaman:是的,如果可能的话,我想使用番石榴,但不使用 eventbus,因为这是针对特定功能的,我想要一种更通用的双重调度方式
  • ChiefTwoPencils:我很好奇你的图书馆,有什么例子吗?

标签: java guava visitor-pattern


【解决方案1】:

不确定“accept() 方法也返回值”是什么意思,但无论如何,在代码生成器的帮助下,访问者模式可以非常轻量:看看https://github.com/derive4j/derive4j - 它提供了一个模式匹配的语法可以使您的代码非常可读。

此外,没有其他技术/库能提供与访问者模式一样多的类型安全性。

【讨论】:

  • 我的意思是“accept() 方法也返回值”:public B accept(Visitor<...> v)....
  • 我敢肯定这很聪明,但这是代码生成吗?我想要一个不生成 java 代码的解决方案。
  • 想知道您避免编译时 (JSR269) 代码生成的理由是什么?对我来说,任何基于运行时反射的解决方案都明显较差(不是类型安全的)。
  • 可能我不知道你说的编译时生成是什么意思,能给我举个例子吗?
  • 示例:JPA2 标准 api 使用 JSR269 注释处理器在编译时生成实体的静态元模型(代码生成由 javac 驱动)。这允许创建类型安全的查询。
【解决方案2】:

您可以制作一个 Map、将 Event 扩展为 key 的类以及将 event 转换为 string 的函数。

Map<Class<T extends Event>,Function<T,String>>

如果你想要一些花哨的东西,你可以使用注解并基于这些注解创建一个注册表(用 spring 很容易做到)但基本上最终结果是一样的。

EventFormatter 根据其类型在映射中查找给定事件的格式化程序并应用相应的函数。 如果您在事件类和格式化程序之间有一对一的映射,那应该没问题。

如果在给定类型没有格式化程序的情况下需要回退到父类,这有点烦人但可行。

【讨论】:

  • 作为一般的解决方案返回值可以是任意类型,不仅仅是字符串,字符串只是举例。
  • 您可以将 String 替换为另一个泛型。类似 Map,Function>
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-24
相关资源
最近更新 更多