1

ExecutorService一連のタスクを処理するために使用される があります。タスクは私のクラスで表され、DaemonTask各タスクは応答呼び出しに渡される応答オブジェクトを作成します (この質問の範囲外)。ステートメントを使用しswitchて、タスク id に基づいて適切なタスクを生成していますint。それは次のようになります。

//in my api listening thread
executorService.submit(DaemonTask.buildTask(int taskID));

//daemon task class
public abstract class DaemonTask implements Runnable {

    public static DaemonTask buildTask(int taskID) {
        switch(taskID) {
            case TASK_A_ID: return new WiggleTask();
            case TASK_B_ID: return new WobbleTask();
            // ...very long list ...
            case TASK_ZZZ_ID: return new WaggleTask();
        }
    }

    public void run() {
        respond(execute());
    }

    public abstract Response execute();
}


すべてのタスク クラス ( などWiggleTask())extend DaemonTaskは、メソッドの実装を提供しますexecute()

私の質問は簡単です。このパターンは合理的ですか?すべての return ステートメントを含む巨大な switch ケースを見ると、何かがおかしいと感じます。何らかの方法でリフレクションを使用して、よりエレガントなルックアップ テーブル ソリューションを考え出そうとしましたが、うまくいくアプローチを見つけられないようです。

4

2 に答える 2

1

次を使用できますenum

public enum TaskBuilder
{
    // Task definitions
    TASK_A_ID(1){
        @Override
        public DaemonTask newTask()
        {
            return new WiggleTask();
        }
    },
    // etc

    // Build lookup map
    private static final Map<Integer, TaskBuilder> LOOKUP_MAP
        = new HashMap<Integer, TaskBuilder>();

    static {
        for (final TaskBuilder builder: values())
            LOOKUP_MAP.put(builder.taskID, builder);
    }

    private final int taskID;
    public abstract DaemonTask newTask();

    TaskBuilder(final int taskID)
    {
        this.taskID = taskID;
    }

    // Note: null needs to be handled somewhat
    public static TaskBuilder fromTaskID(final int taskID)
    {
        return LOOKUP_MAP.get(taskID);
    }
}

このような列挙型を使用すると、次のことができます。

TaskBuilder.fromTaskID(taskID).newTask();

もう 1 つの可能性は、メソッドの代わりにコンストラクター フィールドを使用することです。つまり、リフレクションを使用します。書くのははるかに簡単で、問題なく動作しますが、例外処理は悪夢にほかなりません。

private enum TaskBuilder 
{                                                 
    TASK_ID_A(1, WiggleTask.class),
    // others

    // Build lookup map
    private static final Map<Integer, TaskBuilder> LOOKUP_MAP
        = new HashMap<Integer, TaskBuilder>();

    static {
        for (final TaskBuilder builder: values())
            LOOKUP_MAP.put(builder.taskID, builder);
    }

    private final int index;
    private final Constructor<? extends DaemonTask> constructor;

    TaskBuilder(final int index, final Class<? extends DaemonTask> c)
    {
        this.index = index;
        // This can fail...
        try {
            constructor = c.getConstructor();
        } catch (NoSuchMethodException e) {
            throw new ExceptionInInitializerError(e);
        }
    }

    // Ewww, three exceptions :(    
    public DaemonTask newTask()
        throws IllegalAccessException, InvocationTargetException,
        InstantiationException
    {
        return constructor.newInstance();
    }

    // Note: null needs to be handled somewhat
    public static TaskBuilder fromTaskID(final int taskID)
    {
        return LOOKUP_MAP.get(taskID);
    }
}

この列挙型は、他の列挙型と同じように使用できます。

于 2013-01-03T15:08:15.863 に答える
1

本当にそんなに多くのクラスが必要ですか?taskId ごとに 1 つのメソッドを持つことができます。

final ResponseHandler handler = ... // has many methods.

// use a map or array or enum to translate transIds into method names.
final Method method = handler.getClass().getMethod(taskArray[taskID]); 
executorService.submit(new Callable<Void>() {
    public Void call() throws Exception {
         method.invoke(handler);
    }
});

多くのクラスが必要な場合は、次のことができます

// use a map or array or enum to translate transIds into methods.
final Runnable runs = Class.forName(taskClassArray[taskID]).newInstance(); 
executorService.submit(new Callable<Void>() {
    public Void call() throws Exception {
         runs.run();
    }
});
于 2013-01-03T15:11:11.587 に答える