views:

88

answers:

3

Say I have a Task object, with an Execute method. This method has one to several steps, each of which requires a user to click a 'Continue' button, e.g. when Execute is invoked, the Task tells it's container (a Windows form in this case) to display an introductory message, and wait for a button click, before continuing with step 2, notifying the user that what is taking place and performing some work.

I don't want the controller to have to be aware of the steps in the task, either implicitly, through e.g. calling Execute(Steps.ShowIntro), Execute(Steps.PerformTask) etc. or explicitly, with more than one Execute method, e.g. ExecuteIntro(), ExecuteTask(), etc.

Currently I'm using a Phase enumeration to determine which action to carry out when the Continue button is clicked:

show phase 1 intro.
set current_phase = PhaseOne.
on continue_button click
 switch current_phase
  case PhaseOne:
   show phase 1 'Now doing:' message.
   execute phase 1 task.
   show phase 2 intro.
   set phase to PhaseTwo.
  case PhaseTwo:
   show phase 2 'Now doing:' message.
   execute phase 2 task.
   show phase 3 intro.
   set phase to PhaseThree.
+3  A: 

Why don't you simply implement as many classes with Execute method as steps and put instances of those classes in the queue.

By pressing "Continue" you will take another instance of the class with Execute and call it.

class Task
    method execute()
        foreach task in queue execute task
    method addSubTask( task )
        add task to queue 

class ShowIntroSubTask extends Task
class ExecuteIntroSubTask extends Task
Mykola Golubyev
The usual response is that this means a hell of a lot of boilerplate for anything remotely complicated. But if the IoC system doesn't have a translator to CPS, it's all you can do.
Pete Kirkham
A translator to what, @Pete?
ProfK
@Mykola, your answer still leaves me asking how would I would yield control to the calling method. Executing the sub-tasks in a loop seems no different to me than executing them sequentially. As long as the top level task executes the sub-tasks, my question stands.
ProfK
"I don't want the controller to have to be aware of the steps in the task". Controller won't be aware of the steps. It will be aware of "some" abstract Task. Or did I understand you in a wrong way?
Mykola Golubyev
@ProfK -- The idea is that they are anonymous chunks of work, and their number (and even their nature) can be decided externally at runtime rather than being fossilized in the controller's code at compile time.
MarkusQ
A: 

Mykola's answer sounds good, but if you'd like an alternative, consider passing in a ConfirmContinuation callback, which the Execute could use as needed (e.g. on step transitions). If you wanted to keep things abstract, just call it something like NextStep and leave the semantics up to the container.

MarkusQ
A: 

I wonder if I could not somehow use the yield keyword here, and do a foreach iteration, over my tasks, calling yield when I wish to temporarily return control to the caller?

ProfK