java - 使用注释创建 Callables

  显示原文与译文双语对照的内容
0 0

我试图使一个类似于 https://github.com/ElgarL/TownyChat/blob/master/src/com/palmergames/bukkit/TownyChat/TownyChatFormatter.java的系统。

replacer.registerFormatReplacement(Pattern.quote("{worldname}"), new TownyChatReplacerCallable() {
 @Override
 public String call(String match, LocalTownyChatEvent event) throws Exception {
 return String.format(ChatSettings.getWorldTag(), event.getEvent().getPlayer().getWorld().getName());
 }
 });
 replacer.registerFormatReplacement(Pattern.quote("{town}"), new TownyChatReplacerCallable() {
 @Override
 public String call(String match, LocalTownyChatEvent event) throws Exception {
 return event.getResident().hasTown()? event.getResident().getTown().getName() :"";
 }
 });

等等。

是否使用注释来减少重复代码量,避免反射调用调用方法,如果在注册期间使用它。

我不负责创建一个注释预处理器,因为我已经经计划执行这项操作来自动生成文档。

时间:原作者:4个回答

0 0

假设你写了一个小注解

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@interface PatternHandler {
 String value();
}

并创建类,如

class Callables {
 @PatternHandler("foo")
 public static final TownyChatReplacerCallable FOO = new TownyChatReplacerCallable() {
 @Override
 public String call(String match, String event) {
 return"This is foo handler called with" + match +"," + event;
 }
 };
 @PatternHandler("bar")
 public static final TownyChatReplacerCallable BAR = new TownyChatReplacerCallable() {
 @Override
 public String call(String match, String event) {
 return"This is foo handler called with" + match +"," + event;
 }
 };
}

现在,可以以使用包含这些 static 字段的整个类或者多个类,并将它的传递给一些在该类中反射的注册表。

class AnnotationRegistry {
 public static void register(String pattern, TownyChatReplacerCallable handler) {}
 public static void register(Class<?> clazz) {
//only fields declared by this class, not inherited ones (static fields can't be inherited)
 Field[] fields = clazz.getDeclaredFields();
 for (Field field : fields) {
//must have that annotation
 PatternHandler annotation = field.getAnnotation(PatternHandler.class);
 if (annotation!= null) {
//must be static
 if (!Modifier.isStatic(field.getModifiers())) {
 System.out.println("Field must be static:" + field.getName());
 continue;
 }
//get content of that field
 try {
 Object object = field.get(null);
//must be!= null and a callable
 if (object instanceof TownyChatReplacerCallable) {
 register(annotation.value(), (TownyChatReplacerCallable) object);
 } else {
 System.out.println("Field must be instanceof TownyChatReplacerCallable:" + field.getName());
 }
 } catch (IllegalArgumentException e) {
 e.printStackTrace();
 } catch (IllegalAccessException e) {
 e.printStackTrace();
 }
 }
 }
 }
}

这将为你节省一些代码,并且在运行时没有速度缺点,因为无需使用反射来调用这些 callables 。

这里的完整示例:http://ideone.com/m3PPcY

除了使用 static 字段,如果将类的实例传递给注册表,还可以以使用非 static 类。 Object object = field.get(instance); 而不是 null

这里外,与字段相同的方法将使用 LESS 代码编写的方法:

@PatternHandler("foo")
public static String fooMethod(String match, String event) {
 return"This is foo handler called with" + match +"," + event;
}

注册中心将查找所有的 Method 插件。 然后把它们包装起来

class MethodAdapter implements TownyChatReplacerCallable {
 private final Method method;
 public MethodAdapter(Method m) {
 method = m;
 }
 @Override
 public String call(String match, String event) {
 try {
 return (String) method.invoke(null, match, event);
 } catch (Exception e) {
 e.printStackTrace();
 return"OMGZ";
 }
 }
}

并像往常一样继续。但是请注意: 以反射方式调用方法比直接通过代码调用它要慢得多- 仅仅少数百分比

方法的完整示例:http://ideone.com/lMJsrl

原作者:
0 0

你可以尝试使用新的( http://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html ) 8 Lambda表达式。

replacer.registerFormatReplacement(Pattern.quote("{worldname}"), new TownyChatReplacerCallable() {
 @Override
 public String call(String match, LocalTownyChatEvent event) throws Exception {
 return String.format(ChatSettings.getWorldTag(), event.getEvent().getPlayer().getWorld().getName());
 }
 });

可以编写为:

replacer.registerFormatReplacement(
 Pattern.quote("{worldname}"), 
 (match, event) -> { return String.format(ChatSettings.getWorldTag(), event.getEvent().getPlayer().getWorld().getName()); } 
});

你还可以使用其他接口method方法push进一步推动它。 把它包起来

原作者:
...