[英]Creating Callables using Annotation
我正在嘗試制作類似於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() : "";
}
});
和更多。
有沒有一種方法可以使用注釋來減少重復代碼的數量,避免反射調用調用方法,並且僅在注冊期間使用它(如果有的話)?
我並不反對創建注釋預處理器的想法,因為我已經在計划這樣做以啟用自動生成文檔。
假設您編寫了一個小的注釋
@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;
}
};
}
現在,您可以采用包含這些靜態字段的整個類,甚至多個類,並將其傳遞給某個注冊表方法,該方法對該類中的每個字段進行反射性迭代,如果它是帶注釋的可調用寄存器。
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();
}
}
}
}
}
這將節省您一些代碼,並且在運行時不會對速度造成不利影響,因為不需要使用反射來調用那些可調用對象。
此處的完整示例: http : //ideone.com/m3PPcY
除了使用靜態字段外,如果將類的實例傳遞給注冊表,則也可以使用非靜態字段,然后將其用作Object object = field.get(instance);
而不是null
。
此外,代替字段的是相同的方法,它可以與編寫更少代碼的方法一起使用:
@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
您可以改用新的Java 8 Lambda表達式( http://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html )。
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()); }
});
您還可以通過包裝它的另一個接口,方法...來進一步推動它
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.