3

I'm looking for a good approach to sometimes pause an action (function/method call) until the user confirms that he wants to do a specific part of that action. I need to do this in an environment that doesn't allow code execution to stop (ActionScript in my case, but an approach for JavaScript should be identical).

To illustrate, this is a mock-up of the action before introducing the user prompt:

<preliminary-phase> // this contains data needed by all the following phases //

<mandatory-phase> // this will be always be executed //

<optional-phase> // this will always execute too, if in this form, but in some cases we need to ask the user if he wants to do it //

<ending-phase> // also mandatory //



What I need is to insert a conditional user prompt, a "Do you want to do this part?", and do <optional-phase> only if the user wants to.

<preliminary-phase>

<mandatory-phase>

if(<user-confirmation-is-needed> and not <user-response-is-positive>){
    <do-nothing>
}
else{
    <optional-phase>
}

<ending-phase>



When trying to do this in ActionScript/JavaScript I got something like this:

<preliminary-phase>

<mandatory-phase>

if(<user-confirmation-is-needed>){
    askForConfirmation(callback = function(){
        if(<user-response-is-positive>)
            <optional-phase>
        <ending-phase>
    });
    return;
}

<optional-phase>

<ending-phase>

Now both <optional-phase> and <ending-phase> are duplicated. Also because they use objects created in <preliminary-phase> I can't move them to external functions without passing all the data to those functions.


My current solution is that I enclosed each of <optional-phase> and <ending-phase> in some local functions (so that they have access to data in <preliminary-phase>) declared before I ask for confirmation and I call those functions instead of duplicating the code, but it doesn't seem right that the code is no longer in the order it's executed.

What would you guys recommend?

Notes:
1. askForConfirmation is a non-blocking function. This means that the code that follows its call is executed immediately (this is why I have a return; in my approach).

Alin Purcaru
  • 43,655
  • 12
  • 77
  • 90

4 Answers4

3

Note: I'm not 100% sure I get your exact circumstances.

The Command Pattern might be suitable here. It's similar to what people are suggesting.

You have an array of commands that get executed in order.

[<preliminary-phase>, <mandatory-phase>, <optional-phase>, <ending-phase>]

Just shift the commands off the array one at a time and call the execute method.

In the optional-phase, check to see if the user confirmation is required, if not then execute an optional code method which dispatches a command complete event, if it is required then show the alert, wait for an event, check the result and either dispatch a command complete event or call the optional method (which will run and then dispatch a command complete).

You can also create a tree of commands so can clearly state the flow of execution without having to mess with the array.

This is how programs like installation wizards work.

It's good in that the order of execution is nice and visible and your code is nicely broken down in to chunks, and the complexity of each step is encapsulated. For example, the optional-phase doesn't know anything about the ending-phase. The optional-phase only knows that the user might need prompted before executing and it handles all of that internally.

http://en.wikipedia.org/wiki/Command_pattern

"Using command objects makes it easier to construct general components that need to delegate, sequence or execute method calls at a time of their choosing..."

Joony
  • 4,498
  • 2
  • 30
  • 39
1

"the code is no longer in the order it's executed" seems fine to me actually. It's fine to have code that isn't written in the order it's executed just as long as it's clear. In fact, since your code executes in variable orders I think it's impossible for you to write it in the order it will execute without duplicating code, which is a far greater evil. Pick good function names and your approach would pass my code review.

<preliminary-phase>

<mandatory-phase>

var optional_phase = function() {
  <optional-phase>
}

var ending_phase = function() {
  <ending-phase>
}

if(<user-confirmation-is-needed>){
    askForConfirmation(function(){
        if(<user-response-is-positive>)
            optional_phase();
        ending_phase();
    });
    return;
}

optional_phase();
ending_phase();
Dave Aaron Smith
  • 4,517
  • 32
  • 37
0

Does this do what you're asking for?

<preliminary-phase>

<mandatory-phase>

if(<user-confirmation-is-needed>){
    askForConfirmation(function(){
        if(<user-response-is-positive>)
            <optional-phase-as-local-function>
        <ending-phase-as-local-function>
    });
} else {
    <optional-phase-as-local-function>
    <ending-phase-as-local-function>
}
just mike
  • 1,164
  • 3
  • 12
  • 22
  • What you did by removing the `return` is have `` execute before ``. And that is definitely NOT OK. Please note that the main function will not wait until the user chooses YES/NO it will finish executing all it's code. Also I'm looking for a best-practice. I'm already using a practical solution. – Alin Purcaru Nov 09 '10 at 16:08
  • That would work if `askForConfirmation` blocked like the javascript `confirm` command. However, @Alin says, "I need to do this in an environment that doesn't allow code execution to stop." I think that means his `askForConfirmation` won't block which means that if confirmation is needed your solution here will execute `` before `` – Dave Aaron Smith Nov 09 '10 at 16:09
  • sorry, i was thinking in "JavaScript" and didn't realize the blocking issue. how about the current edit? – just mike Nov 09 '10 at 16:21
  • How is it different from the 3rd code block in the question? It seems you didn't understand what I'm asking for :) . I'm already doing what you suggest. The *question* is whether there is a better option. – Alin Purcaru Nov 09 '10 at 16:29
  • yep, you're right. sorry. should have paid more attention to the ActionScript part and let more knowledgeable people answer. i've lost some self-confidence now, and i'm not an ActionScript person, so not sure what this is worth, but i think the answer is: you're doing it right. – just mike Nov 09 '10 at 16:39
  • Input is always welcomed. Of course, I'm hoping for some arguments, but it seems the AS community on SO is not too active. – Alin Purcaru Nov 09 '10 at 16:43
0

Not a huge change , but provided this flow works, optional phase is not repeated

<preliminary-phase>

<mandatory-phase>

if(<user-confirmation-is-needed>){
    askForConfirmation(function(){
      if(<user-response-is-negative>)
      {
        <ending-phase>
        return;
      }
  });
}

<optional-phase>
<ending-phase>
PatrickS
  • 9,539
  • 2
  • 27
  • 31