Chaining tasks using generics
I am trying to create an API for chaining tasks.
First, I designed a very simple interface defining a task:
public interface Task<U, V> {
U execute(V input);
}
Where V
is the input type and U
the output type of the task.
What I whish to create is a Chain
class that would开发者_如何学Python chain a list of Tasks
.
For instance, I would like to execute: Task1<TypeA, TypeB> -> Task2<TypeB, TypeC> -> Task3<TypeC, TypeD>
This Chain
class would thus be a Task<TypeA, TypeD>
.
So I wrote this code, which does not compile :
public class Chain<U, V> implements Task<U, V> {
List<Task<?, ?>> taskList;
public Chain() {
taskList = new LinkedList<Task<?, ?>>();
}
@Override
public U execute(V input) {
V currentInput = input;
U output = null;
for (Task<?, ?> task : taskList) {
output = task.execute(currentInput);
// Compile error because currentInput is of type V
// and output of type U
currentInput = output; // Compile error as well
}
return output;
}
// Other methods to add and remove tasks in the list
}
I do understand why it cannot compile but I have no idea how I could implement something that works and answers my problem.
Has anyone ever faced this kind of problem?
Kind regards,
Ben
Your Task
class is pretty much the same as the Guava class Function
. You could use that instead of defining your own one.
An advantage of using Function
would be that you could use the helper methods in the Functions
class, one of which is compose()
:
Function<String,MyObject1> stringToMyObject1 = ...;
Function<MyObject1, AnotherObject> myObject1ToAnotherObject = ...;
Function<String,AnotherObject> stringtoAnotherObject = Functions.compose(myObject1ToAnotherObject, stringToMyObject1);
Deeper chaining can be achieved by repeated calls to compose()
.
Even if you don't want to use Guava for some reason, you can take inspiration from this approach: chaining any two functions/task with known type arguments creates a new function/task with easily-calculated type arguments.
Instead of trying to maintain the tasks in a (nongeneric) list, you could try the "decorator" approach (for lack of better word), i.e. define a class which takes another task as a parameter, executes some task then passes its result to the other task. Or as a composite, which takes two tasks, and passes the output of the first as input to the 2nd.
Try the following. The problem you have is that your output cannot be V and U at the same time.
public U execute(V input) {
Object object = input;
for (Task task : taskList)
object = task.execute(object);
return (U) object;
}
精彩评论