# Thinking in Commands: Part 1 of 2

Twice a month, we revisit some of our readers’ favorite posts from throughout the history of Activetuts+. This tutorial was first published in March, 2010, and is the first part of a series.

Simple, maintainable code is beautiful. However, when we have a sequences of actions that need to trigger each other, our code can get messy, making it impossible to change later. The Command Pattern keeps things clean.

In this tutorial, I'll show you how to create a minimalist AS3 Command framework, capable of performing actions in sequence, in parallel, or with a delay. You'll lean how to use this framework to create a complex effect with simple and clean code.

## Command Encapsulation

Encapsulating instructions into "commands" is a popular programming approach to simplify things - the Command Pattern is actually one of the most commonly used design patterns in object-oriented programming. Basically, the command concept is implemented by creating command classes, each class representing one type of command. In the rest of the tutorial, when I refer to "a command", I mean "a command object".

You can think of a command as a button on a remote control. Each button does something different, but they're all used in the same way: you press it, then the magic happens. Be it turning the TV on, changing the channels, or adjusting the volume, these functions can all be done by simply pressing a button.

Image courtesy of freedigitalphotos.net

The concept of commands is the same. A command's underlying instruction is just like a remote control button's function. You may encapsulate different instructions into commands, such as tracing out a simple message, moving one object from one place to another, or toggling the visibility of a display object. Once the encapsulation is done, these can be performed simply by telling the program to "press the remote control buttons", or in other words, to "execute the commands".

If you want the program to perform differently, you can just change the code inside the Command class: the program still executes the same commands it did previously, but the underlying code inside the commands is different. Your overall list of the actions that you want the program to do is separate from your detailed list of instructions for how each action should be done.

## Why Bother with Commands?

"Big deal," you might say, "I could do that using functions. Why bother using commands?" Okay, let's look at two sets of code that create the same effect, one using functions, and the other using the command framework we'll create in this tutorial. The advantage of commands will become clear.

Let's say we want to create a circle, add it to the stage, tween it from invisible to visible over half a second, wait for two seconds, tween back to invisible over another half second, and then remove it from the stage. To do all this we'll use Greensock's TweenNano class.

If you're only using functions, the code will look like this:

 1 2 var circle:Circle = new Circle();  3 addChild(circle);  4 TweenNano.from(circle, 0.5, {alpha:0, onComplete:func1});  5 6 function func1():void {  7  TweenNano.to(circle, 0.5, {delay:2, alpha:0, onComplete:func2});  8 }  9 10 function func2():void {  11  removeChild(circle);  12 } 

Do you see how our list of actions is all tangled up with our instructions for performing each action? To figure out what's going to happen, you have to follow all the onCompletes and see where they lead.

Here's the same code, using a command framework:

 1 2 var circle:Circle = new Circle();  3 4 var command:Command =  5  new SerialCommand(0,  6  new AddChild(this, circle),  7  new TweenNanoFrom(circle, 0.5, {alpha:0}),  8  new TweenNanoTo(circle, 0.5, {delay:2, alpha:0}),  9  new RemoveChild(this, circle)  10  );  11   12 command.start(); 

Here, AddChild(), TweenNanoFrom, TweenNanoTo, and RemoveChild are all Command classes that we define elsewhere in the code, and SerialCommand is another Command class we can use to create sequences of commands on the fly.

Result: no more function "jumps". It's clear what this sequence is going to do, and in what order. It's also easy to change the order of the actions, or insert a new action between existing ones, without having to hunt around the code for each action and change its onComplete property.

Commands also let us queue up different actions so that they happen at the same time - but we'll get to that later!

## The Command Class

A quick working example is worth more than a thousand words, so let's look at the essential element of our command framework: the Command class.

 1 2 package commands {  3  import flash.events.Event;  4  import flash.events.EventDispatcher;  5  import flash.events.TimerEvent;  6  import flash.utils.Timer;  7   8  public class Command extends EventDispatcher {  9   10  private var _timer:Timer;  11   12  public function Command(delay:Number = 0) {  13  _timer = new Timer(int(1000 * delay), 1);  14  _timer.addEventListener(TimerEvent.TIMER_COMPLETE, onTimerComplete);  15  }  16   17  private function onTimerComplete(e:TimerEvent):void {  18  execute();  19  }  20   21  /**  22  * Starts the command.  23  * Waits for the timer to complete and calls the execute() method.  24  * This method can be used directly as an event listener.  25  */  26  public final function start(e:Event = null):void {  27  _timer.start();  28  }  29   30  /**  31  * The abstract method for you to override to create your own command.  32  */  33  protected function execute():void {  34   35  }  36   37  /**  38  * Completes the command.  39  * Dispatches a complete event.  40  * This method can be used directly as an event listener.  41  */  42  protected final function complete(e:Event = null):void {  43  dispatchEvent(new Event(Event.COMPLETE));  44  }  45  }  46 } 

The "emptiest" method is the execute() method; however, this method is the most important part of the command. In order to create various command objects, you have to extend this Command class and override the execute() method, filling in the instructions you want your program to perform.

To make a Command object work, you call its start() method; it counts down the delay time using a Timer object, and calls the execute() method when the timer finishes the count-down. A zero delay time simply means your Command object's execute() method will be called right after you call its start() method.

(Note that when your command is complete, you have to call the complete() method manually, causing it to dispatch a COMPLETE event. The purpose of this method would become clear later in the tutorial.)

By the way, setting up the event parameter for the start() and complete() methods with a null default value is just my personal habit. In this way, the methods can be called like you would do to any other zero-parameter methods, or can be used directly as event listeners.

## Example: Simple Tracing

Now that we have our Command class, let's start playing with it with some simple tracing.

## Step 1: Create a Flash Document

First off, we have to open the Flash IDE and create a new Flash document. Call it SimpleTracing.fla.

## Step 2: Create the Document Class

Next, create a document class for this Flash document. Read this Quick Tip for an introduction to document classes.

 1 2 package {  3  import flash.display.Sprite;  4   5  public class SimpleTracing extends Sprite {  6   7  public function SimpleTracing() {  8   9  }  10  }  11 } 

Save it as SimpleTracing.as.

## Step 3: Create the Base Command Class

Create a new AS file and copy the Command class (from above) into it.

Create a new folder in your classpath called "commands" and save this new AS file as Command.as inside that folder.

## Step 4: The Trace Command

We'd like to start by encapsulating a tracing function into commands, so let's extend the Command class to create a TraceCommand class for this purpose. This class will contain a message string to be traced out when the execute() method is called, and will call the complete() method after the tracing.

 1 2 package commands {  3   4  public class TraceCommand extends Command {  5   6  private var _message:String;  7   8  public function TraceCommand(delay:Number, message:String) {  9  super(delay);  10  _message = message;  11  }  12   13  override protected function execute():void {  14  trace(_message);  15  complete();  16  }  17  }  18 } 

Save this as TraceCommand.as, also in the "commands" folder. See how we've overridden the execute() function to make this command actually do something?

## Step 5: Trace

Complete the document class with TraceCommand objects. Add listeners for the COMPLETE event of these commands.

 1 2 package {  3  import commands.Command;  4  import commands.TraceCommand;  5  import flash.display.Sprite;  6  import flash.events.Event;  7   8  public class SimpleTracing extends Sprite {  9   10  public function SimpleTracing() {  11   12  var command:Command;  13   14  command = new TraceCommand(0, "first command");  15  command.addEventListener(Event.COMPLETE, onCommandComplete);  16  command.start();  17   18  command = new TraceCommand(1, "second command");  19  command.addEventListener(Event.COMPLETE, onCommandComplete);  20  command.start();  21   22  command = new TraceCommand(2, "third command");  23  command.addEventListener(Event.COMPLETE, onCommandComplete);  24  command.start();  25  }  26   27  private function onCommandComplete(e:Event):void {  28  trace("a command is complete");  29  }  30  }  31 } 

Telling the program to execute the commands is as simple as calling the Command objects' start() methods. Test the movie and you'll see the following output, printed out line-by-line with a time gap of one second. Also, you can see the interlacing messages printed out by the commands' complete event listener. The same variable is used to hold references to different Command objects, but the program does the same thing to the variable: call the start() method and listen for a COMPLETE event.

## Composite Commands

There are times when you'd like to execute multiple commands with complex timing. Here I'll introduce two common types of commands which can accomplish advanced command timing: parallel and serial commands. Both of these are composite commands, which means they contain multiple subcommands. Let's check them out one by one.

## Parallel Command

A parallel command executes all its subcommands at the same time - or, in other words, in parallel. The command is complete only when all its subcommands are complete. The following figure gives a visual concept of a parallel command. The black arrowheads denote the "flow" of command execution

## The ParallelCommand Class

Now it's time to create our class for parallel commands.

Below is the complete code for the ParallelCommand class. Save it as ParallelCommand.as in your "commands" folder.

The subcommands are passed to the constructor as the ...(rest) parameter. This lets us pass as many commands as we like to the constructor; they'll automatically be put into an array called commands. We'll see the beauty of this special type of parameter very shortly.

 1 2 package commands {  3  import flash.events.Event;  4   5  public class ParallelCommand extends Command {  6   7  private var _commands:Array;  8   9  public function ParallelCommand(delay:Number, ...commands) { //...commands is the "...(rest)" parameter  10  super(delay);  11  _commands = commands;  12  }  13   14  private var _completeCommandCount:int;  15   16  override final protected function execute():void {  17   18  //set the complete command count to zero  19  _completeCommandCount = 0;  20   21  for each (var command:Command in _commands) {  22   23  //listen for the complete event of a subcommand...  24  command.addEventListener(Event.COMPLETE, onSubcommandComplete);  25   26  //...and start the subcommand  27  command.start();  28  }  29  }  30   31  private function onSubcommandComplete(e:Event):void {  32   33  //stop listening for the complete event  34  Command(e.target).removeEventListener(Event.COMPLETE, onSubcommandComplete);  35   36  //increment the complete command count  37  _completeCommandCount++;  38   39  //if all the commands are complete...  40  if (_completeCommandCount == _commands.length) {  41   42  //...then this parallel command is complete  43  complete();  44  }  45  }  46  }  47 } 

This class overrides the execute() method; the new execute() method now calls the start() method of all subcommands, and listens for their COMPLETE events. The COMPLETE event listener for the subcommands counts how many subcommands have completed; once all the subcommands are done, the ParallelCommand's complete() method is called, and dispatches a COMPLETE event of its own.

## Example: Parallel Tracing

Let's try out the ParallelCommand class. Create a new Flash document, copy the "commands" folder to its classpath, and write a new document class as below:

 1 2 package {  3  import commands.Command;  4  import commands.ParallelCommand;  5  import commands.TraceCommand;  6  import flash.display.Sprite;  7  import flash.events.Event;  8   9  public class ParallelTracing extends Sprite {  10   11  public function ParallelTracing() {  12   13  var parallelCommand:Command =  14  new ParallelCommand(0,  15  new TraceCommand(0, "1st of 3"),  16  new TraceCommand(0, "2nd of 3"),  17  new TraceCommand(0, "3rd of 3"),  18  );  19   20  parallelCommand.addEventListener(Event.COMPLETE, onCommandComplete);  21   22  parallelCommand.start();  23  }  24   25  private function onCommandComplete(e:Event):void {  26  trace("all commands are complete");  27  }  28  }  29 } 

The benefit of using the "...(rest)" parameter for the constructor parameter now becomes apparent. You can format the subcommands with proper code indentation to write visually self-explanatory codes.

Test the movie and you'll see the three messages traced out at the same time, then a final message denoting the completion of the parallel command:

• 1st of 3
• 2nd of 3
• 3rd of 3
• all commands are complete

What about setting up delays within a parallel command? Simple. Change your document class's constructor function like so:

 1 2 public function ParallelTracing() {  3   4  var parallelCommand:Command =  5  new ParallelCommand(0,  6  new TraceCommand(0, "first wave, 1st of 2"),  7  new TraceCommand(0, "first wave, 2nd of 2"),  8  new TraceCommand(1, "second wave, 1st of 3"),  9  new TraceCommand(1, "second wave, 2nd of 3"),  10  new TraceCommand(1, "second wave, 3rd of 3"),  11  new TraceCommand(2, "last wave, 1st of 2"),  12  new TraceCommand(2, "last wave, 2nd of 2")  13  );  14   15  parallelCommand.addEventListener(Event.COMPLETE, onCommandComplete);  16   17  parallelCommand.start();  18 } 

Test the movie and you'll see the following three waves of messages printed out, with a one-second time gap between each wave:

• first wave, 1st of 2
• first wave, 2nd of 2

• second wave, 1st of 3
• second wave, 2nd of 3
• second wave, 3rd of 3

• last wave, 1st of 2
• last wave, 2nd of 2

To get a better idea of what's going on, check out this illustration:

## Serial Command

The second type of composite command is the serial command. A serial command executes its subcommands one after the other - or, in other words, in series. For instance, the second command is executed after the completion of the first one and the third one is executed after the completion of the second one. The following figure gives a visual concept of a serial command:

## The SerialCommand Class

Here's the source code for the SerialCommand Class. The overridden execute() method calls the start() method of the first subcommand and listens for its COMPLETE event. Then, the event listener starts the next subcommand and listens for its COMPLETE event, and so on, until all subcommands are completed. At that point, the COMPLETE event for the whole SerialCommand is dispatched.

 1 2 package commands {  3  import flash.events.Event;  4   5  public class SerialCommand extends Command {  6   7  private var _commands:Array;  8   9  public function SerialCommand(delay:Number, ...commands) {  10  super(delay);  11  _commands = commands;  12  }  13   14  private var _completeCommandCount:int;  15   16  override final protected function execute():void {  17   18  //set the complete command count to zero  19  _completeCommandCount = 0;  20   21  //listen for the complete event of the first subcommand...  22  _commands[0].addEventListener(Event.COMPLETE, onSubcommandComplete);  23   24  //...and start the subcommand  25  _commands[0].start();  26  }  27   28  private function onSubcommandComplete(e:Event):void {  29   30  //stop listening for the complete event  31  Command(e.target).removeEventListener(Event.COMPLETE, onSubcommandComplete);  32   33  //increment the complete command count  34  _completeCommandCount++;  35   36  //if all the commands are complete...  37  if (_completeCommandCount == _commands.length) {  38   39  //...then this serial command is complete  40  complete();  41  } else {  42   43  //...otherwise listen for the complete event of the next subcommand...  44  _commands[_completeCommandCount].addEventListener(Event.COMPLETE, onSubcommandComplete);  45   46  //...and start the subcommand  47  _commands[_completeCommandCount].start();  48  }  49  }  50  }  51 } 

## Example: Serial Tracing

Let's use the SerialCommand class to do some serial tracing. As before, create a new Flash document, copy the "commands" folder over, and write a new document class:

 1 2 package {  3  import commands.Command;  4  import commands.SerialCommand;  5  import commands.TraceCommand;  6  import flash.display.Sprite;  7  import flash.events.Event;  8   9  public class SerialTracing extends Sprite {  10   11  public function SerialTracing() {  12   13  var serialCommand:Command =  14  new SerialCommand(0,  15  new TraceCommand(0, "first command"),  16  new TraceCommand(1, "second command"),  17  new TraceCommand(1, "third command")  18  );  19   20  serialCommand.addEventListener(Event.COMPLETE, onCommandComplete);  21   22  serialCommand.start();  23  }  24   25  private function onCommandComplete(e:Event):void {  26  trace("all commands are complete");  27  }  28  }  29 } 

Test the movie and the following messages are traced out one-by-one, with a one-second time gap, followed by "all commands are complete".

• first command

• second command

• third command

Here's a concept figure of this example that helps you have a better understanding of what's going on.

## Nested Composite Commands

So far, we've only explored the most basic usage of parallel and serial commands, and there doesn't seem to be any point to use them instead of separate commands. However there are times when you need much more complex command executions, and you may combine multiple composite commands to create nested commands to fit your needs. The next example demonstrates how to use the ParallelCommand class and SerialCommand class to create such nested commands.

## Example: Nested Commands

As before, create a new Flash document, copy the "commands" folder over, and write a new document class:

 1 2 package {  3  import commands.Command;  4  import commands.ParallelCommand;  5  import commands.SerialCommand;  6  import commands.TraceCommand;  7  import flash.display.Sprite;  8  import flash.events.Event;  9   10  public class NestedCommands extends Sprite {  11   12  public function NestedCommands() {  13   14  var nestedCommands:Command =  15  new SerialCommand(0,  16  new ParallelCommand(0,  17  new TraceCommand(0, "parallel command #1, part 1 of 2"),  18  new TraceCommand(0, "parallel command #1, part 2 of 2"),  19  new TraceCommand(0, "--------------------------------")  20  ),  21  new ParallelCommand(1,  22  new TraceCommand(0, "parallel command #2, part 1 of 3"),  23  new TraceCommand(0, "parallel command #2, part 2 of 3"),  24  new TraceCommand(0, "parallel command #2, part 3 of 3"),  25  new TraceCommand(0, "--------------------------------")  26  ),  27  new ParallelCommand(1,  28  new TraceCommand(0, "last command"),  29  new TraceCommand(0, "--------------------------------")  30  )  31  );  32   33  nestedCommands.addEventListener(Event.COMPLETE, onCommandComplete);  34   35  nestedCommands.start();  36  }  37   38  private function onCommandComplete(e:Event):void {  39  trace("all commands are complete");  40  }  41  }  42 } 

Test the movie and the program will print out the following message chunks one-by-one, with a one-second time gap. As in the previous examples, a final complete message will be printed out when all the subcommands are complete.

• parallel command #1, part 1 of 2
• parallel command #1, part 2 of 2
• --------------------------------

• parallel command #2, part 1 of 3
• parallel command #2, part 2 of 3
• parallel command #2, part 3 of 3
• --------------------------------

• last command
• --------------------------------

Here's the concept figure of this example.

## Example: Light Circuit

Finally, let's look at a more practical example. We're going to use the command framework we've built to create a light circuit demo, with advanced timing. Before we start, (you guessed it) create a new Flash document, copy the "commands" folder over, and create a new document class.

## Step 1: The Light Symbol

Create a movie clip symbol, with a timeline animation where a circle changes its color from gray to yellow.

In the timeline, at the last keyframe, add the following code. This causes the movie clip to stop animating and dispatch a COMPLETE event:

 1 2 stop();  3 dispatchEvent(new Event(Event.COMPLETE)); 

If you want to avoid coding on the timeline, you can create a class for your light movieclip, with a function:

 1 2 public function reachedEndOfAnimation():void  3 {  4  stop();  5  dispatchEvent(new Event(Event.COMPLETE));  6 } 

...and then in the constructor for that class, write the following:

 1 2 addFrameScript(4, reachedEndOfAnimation) //where 4 is one less than the number of frames 

## Step 2: The Circuit

Arrange light instances on the stage and name them as the following figure shows:

## Step 3: Interaction

Drag a Button component from the Components Panel onto the stage and name it "start_btn". We want to execute our commands when this button is pressed.

## Step 4: Completion Indicator

Create a text field on the stage and type in your completion message. Next, convert it to a movie clip symbol, and name the instance "completeMessage_mc".

## Step 5: The Document Class

Now it's time to edit the document class. Declare a private variable "circuitCommand", which will be used to hold a reference to a Command object:

 1 2 private var circuitCommand:Command; 

At the beginning of the program, all lights shall be turned off, i.e. stopped at the first frame, and the completion message should be hidden. So we call the reset() method in the constructor.

 1 2 reset(); 

Then, create our nested commands that play the light movie clips' animations, lighting them up with proper timing. We use a PlayCommand class here, which simply calls a movie clip's play() method. We'll write the class later.

 1 2 circuitCommand =  3  new SerialCommand(0.5,  4  new PlayCommand(0, light_1),  5  new ParallelCommand(0.5,  6  new PlayCommand(0, light_2_1),  7  new PlayCommand(0, light_2_2)  8  ),  9  new PlayCommand(0.5, light_3),  10  new ParallelCommand(0.5,  11  new PlayCommand(0, light_4_1),  12  new PlayCommand(0, light_4_2)  13  ),  14  new PlayCommand(0.5, light_5)  15  ); 

Next, listen for the COMPLETE event of the command and the CLICK event of the start button:

 1 2 circuitCommand.addEventListener(Event.COMPLETE, onCommandComplete);  3 start_btn.addEventListener(MouseEvent.CLICK, startCircuit); 

## Step 6: Add Event Handlers

Show the completion message when the command is complete:

 1 2 private function onCommandComplete(e:Event):void {  3  completeMessage_mc.visible = true;  4 } 

Reset the circuit and start the command when the start button is clicked.

 1 2 private function startCircuit(e:MouseEvent):void {  3  reset();  4  circuitCommand.start();  5 } 

## Step 7: The Reset Method

The last part for the document class is the reset() method. Nothing to do with commands here.

 1 2 private function reset():void {  3  completeMessage_mc.visible = false;  4   5  light_1.gotoAndStop(1);  6  light_2_1.gotoAndStop(1);  7  light_2_2.gotoAndStop(1);  8  light_3.gotoAndStop(1);  9  light_4_1.gotoAndStop(1);  10  light_4_2.gotoAndStop(1);  11  light_5.gotoAndStop(1);  12 } 

## Step 8: The PlayCommand Class

The last part of this example is the PlayCommand class. As mentioned before, what it does is as simple as calling a movie clip's play() method. As soon the play() method is called in the command's overridden execute() method, the complete() method is also called.

 1 2 package commands {  3  import flash.display.MovieClip;  4  import flash.events.Event;  5   6  public class PlayCommand extends Command {  7   8  private var _movieClip:MovieClip;  9   10  public function PlayCommand(delay:Number, movieClip:MovieClip) {  11  super(delay);  12  _movieClip = movieClip;  13  }  14   15  override protected function execute():void {  16  _movieClip.addEventListener(Event.COMPLETE, complete);  17  _movieClip.play();  18  }  19  }  20 } 

Save this as PlayCommand.as in your "commands" folder.

## Step 9: Test the Movie

All right, we're done! Now test the movie and you'll see the lights being lit up from left to right after the start button is clicked. The completion message is shown when all the lights are lit up.

Here's the visual representation of what's going on in this Example:

Compare it to the actual code, and see how easy it is to understand:

 1 2 new SerialCommand(0.5,  3  new PlayCommand(0, light_1),  4  new ParallelCommand(0.5,  5  new PlayCommand(0, light_2_1),  6  new PlayCommand(0, light_2_2)  7  ),  8  new PlayCommand(0.5, light_3),  9  new ParallelCommand(0.5,  10  new PlayCommand(0, light_4_1),  11  new PlayCommand(0, light_4_2)  12  ),  13  new PlayCommand(0.5, light_5)  14 ); 

Again, with proper code indentation, a complex nested command can be expressed as simple and clean code.

## Summary

In this tutorial you've learned the concept of commands. Instructions can be encapsulated into commands which have identical interfaces, just like each button on a remote control has a different action, but the method to invoke each action is the same: press the button.

Also, this tutorial introduced you to two types of composite commands: parallel and serial. These can be used to create nested commands allowing for advanced command execution timing while keeping code clean.

## Conclusion

The concept of commands is very convenient and powerful. Code encapsulation is the main approach to simplify things out while programming, and one of the most commonly used methods is the use of command objects. I hope this tutorial helps you understand better how to use commands in practical applications.

In the next part of this tutorial, I'll show you how to integrate TweenLite with the command framework we created in this tutorial, then handle scene transitions with simple and clean code. Thank you very much for reading.