2

To make my question more concrete, let me pose it as a problem:

situation description:

We have 3 abstract concepts:

Boss:  which has a number of employees
Worker:  that can execute some types of tasks
Task:  contains the semantics needed for a worker to execute it

In the implementation/subtypes we have a number of different types of workers and different types of tasks. A specific type of worker can execute certain types of tasks (subset of all types)

problem to solve

Now the boss has a task of known type he wishes to see executed, he does not know the types of workers he has (only abstract type/interface). What kind of interface(s) could the worker implement/what could the boss do to find out?

ways to solve it that I can think of

I found this two ways, but there probably are other&better ways:

1) we make an class for every task type implementing the empty task interface give the worker an execute(task) function: in the implementation of execute(task) try to typecheck/cast task to all tasktypes that type of worker can perform. If none of the typechecks pass, we throw a taskNotSupportedException. the boss can now give tasks to workers until no exception is thrown.

2) we now do not have task classes but define an capability interface for every task type with the function dotaskType(taskinfo) a worker implementation can now implement capability interfaces dependant of what its capabilities are. the boss now can check until a worker with the proper capability is found (typechecking) and then give him the task knowing he can execute it.

I did not test 2 and I do not have that much experience in java but this should be possible (or something very similar).

I also prefer 2 over 1, because 1 seems improper (cascade of casts) and interfaces are a natural way to define what an instance of a class can do, also with interfaces you could group capabilities/create hierarchies. (also in my current implementation (1) the Task interface is empty, so tasks do not have much in common and info is passed through the constructor (which would be parameters of functions in method 2) and retrieved by gets.

I was wondering in what other way you would/could implement (adjusting 1 or 2?) this or which of the two you prefer and why. (efficiency is not important, modulation/abstraction/maintainability is!)

codelidoo
  • 219
  • 1
  • 11
  • Suggestion: make the boss a contractor and the workers specialists like painters, carpenters and gardeners. Then let's say they have to do a home makeover from kitchen sink to garden gnomes to interior decoration. – Gressie Apr 28 '11 at 18:29

2 Answers2

2

Don't use exceptions for this. Exceptions should be used for exceptional situations, and not being able to perform some task seems to be normal.

I would add a method

boolean isAbleToExecute(Task task)

in the Worker class, and have the boss iterate through his workers and find a worker able to execute the task before assigning it.

JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
  • I was about to suggest this too, then saw it was already there. Ideally you would collect all workers that can execute it and then somehow figure out the first one that do it. – Gressie Apr 28 '11 at 18:32
  • Yeah adding that method also came to mind. And in method 1 this is a good idea, but I don't really like method 1 it seems improper (cascade of casts,...). About that Exception, I think it should be there, just because it is a case that needs to be handled somehow and I don't see a way for the worker to deal with this problem other than throwing an exception (aka telling his boss). What is your viewpoint on method 2? – codelidoo Apr 28 '11 at 19:18
0

Worker interface could include a method supportedTasks returning a list of tasks. Then you could maintain a Map, mapping task to list of workers supporting that task. Then your boss doesn't need to iterate, but can simply look up all workers that supports a given task.

Buhb
  • 7,088
  • 3
  • 24
  • 38
  • The average number of workers will be small, so there is not much overhead in iterating them (what I meant with efficiency is not important). Yet from coding point of view I like the isAbleToExecute better (maybe because the name starts with a verb ;) How about method 2? Or some other way it could be done (must not be clearly superior, any ideas are good) – codelidoo Apr 28 '11 at 19:33
  • If I understand method 2 correctly, you want something like if (worker instanceof taskCapability) ((taskCapability) worker).doTaskType(task); This type checking and casting doesn't feel very clean. Workers should supply means to know what tasks they can execute. Either isAbleToExecute and supportedTasks works fine, but if I was a boss, I'd like my workers indexed in a way that made sense to me. And if supportedTasks returns a Set of tasks, the isAbleToExecute is easily implemented with supportedTasks.contains(task) – Buhb Apr 28 '11 at 21:34
  • You understood correctly, yet in method 1 the same kind of typechecking and casting is performed by the worker which is weird because he got a clear task from the boss, just because it was passed trough execute(Task). Also it is weird to define WHAT(!=HOW) a class can do in its implementation instead of in its interface. Don't you think method 1 leads to harder to maintain code, since the programmer wanting to add a task would have to do so in 2 seperate methods (what if he forgets 1???), while in method 2 implementing the interface forces the programmer to define the function. – codelidoo Apr 29 '11 at 00:29