Java ExecutorService任务产生

时间:2013-01-03 15:04:42

标签: java coding-style refactoring executorservice

我有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()方法的实现。

我的问题很简单;这种模式合理吗?当我看到我的巨大开关盒及其所有返回语句时,感觉有些不对劲。我试图以某种方式使用反射来提出一个更优雅的查找表解决方案,但似乎无法找到一种可行的方法。

2 个答案:

答案 0 :(得分: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();

另一种可能性是使用构造函数字段而不是方法,即使用反射。编写起来要容易得多,而且工作正常,但异常处理就变成了噩梦:

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

这个枚举可以和其他枚举一样使用。

答案 1 :(得分:1)

你真的需要这么多课吗?每个taskId可以有一个方法。

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();
    }
});