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

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

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

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

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 可以有一个方法。

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 回答