1

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

2 に答える 2

1

小さな注釈を書いたとしましょう

@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;
}

次に、レジストリはすべての s を探します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

于 2013-07-25T22:23:06.063 に答える
0

代わりに、新しい Java 8 ラムダ式を試すことができます ( 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()); } 
});

それをラップする別のインターフェース、メソッドなどでさらにプッシュすることもできます

于 2013-07-25T13:24:38.187 に答える