我有一个应用程序,它有许多声明的lambda。我给它们添加了一个注释,这样我就可以使用反射来查找带有注释标记的所有函数。它们都被定义为:
@FooFunction("abc")
public static Function<Task, Result> myFunc = task -> {... returns new Result}
在启动时,我的应用程序使用反射来查找所有带注释的函数并将它们添加到hashmap中。
static HashMap<String, Function<Task, Result>> funcMap = new HashMap<>();
static {
Reflections reflections = new Reflections("my.package", Scanners.values());
var annotated = reflections.getFieldsAnnotatedWith(FooFunction.class);
annotated.forEach(aField -> {
try {
var annot = aField.getAnnotation(FooFunction.class);
var key = annot.value();
funcMap.put(key, aField.get(null);
} catch (Exception e) {
...;
}
}
上面的代码肯定不会工作,特别是在放,因为affield .get(null)返回一个对象。如果我将对象强制转换为Function<Task,Result>,就会得到未检查强制转换警告。不管我怎么把它圈起来,我都无法去掉这个警告(除非使用Suppress)。
我试过改变函数<Foo,>变成了更普通的东西,比如Function<?,?>
,但这又让我掉进了另一个兔子洞。
所有的函数都声明为静态的,因为它们确实不需要属于特定的类。为了便于组织,它们被归为不同的类。
底层目标是:API将接收一个任务列表。大约有100种不同的任务类型。每个Task都有一个"id"。字段,用于确定应该使用哪个函数来处理该任务。它看起来像这样:
var results = Arrays.stream(request.getTasks())
.map(task -> functionMap.getOrDefault(task.getId(), unknownTaskFn).apply(task)
.toList();
我的问题:
- 这是一个反模式吗?如果有,有没有更好的规定模式?
- 如何从对象转换为函数<任务,结果>把它放到地图上合适吗?
强制转换是不可避免的,因为Field.get
在设计上返回Object
,但它可以在没有警告的情况下完成。
我还建议定义一个自定义接口
public interface TaskResultFunction extends Function<Task, Result> {
}
并将其用于lambda声明
@FooFunction("abc")
public static TaskResultFunction myFunc = task -> {... returns new Result}
(否则我们将不得不处理parameterizedtyperefence,但在这种情况下,它不是必要的,而且过于复杂)
Map<String, Function<Task, String>> funcMap = ...
// or more strict
Map<String, TaskResultFunction> funcMap = ...
//...
if (TaskResultFunction.class.isAssignableFrom(field.getType())) {
TaskResultFunction fn = (TaskResultFunction) field.get(null);
taskResultFunctions.put(key, fn);
}