Channels ▼
RSS

JVM Languages

Java ME and the Command Pattern

Source Code Accompanies This Article. Download It Now.


Darius is a Java consultant at Jayway AB, a Java knowledge company in Sweden. He can be contacted at darius.katz@jayway.se.


Command actions in Java ME are handled by the MIDlet class's commandAction() method. While the approach shown in Listing One is quick, neat, and compact, it is also difficult to extend and reuse. The more commands you add, the longer the if-else chain grows—and if you want to use the same command on another screen or canvas, you have to copy-and-paste code, which is difficult to maintain.

public void commandAction(Command command, Displayable d) {
   if (command == firstCommand) {
      textBox.setString("First command executed");
   } else if (command == secondCommand) {
      textBox.setString("Second command run");
   } else if (command == thirdCommand) {
      textBox.setString("Third command chosen");
   } else if (command == exitCommand) {
      notifyDestroyed();
   }
}

Listing One

Luckily, the Command Pattern provides an efficient workaround for these problems. The essence of the Command Pattern is to divide the part where the command is implemented from the part where it is invoked (using a predefined interface, of course; this is object orientation after all). This is done by putting the code behind each command in a separate object, then calling it when it is time.

In Pattern lingua, this translates to: "Encapsulate a request as an object..." (see Design Patterns: Elements of Reusable Object-Oriented Software by Erich Gamma et al., Addison-Wesley, 1995) and "the invoker that issues a request on behalf of the client and the set of service-rendering Receiver objects can be decoupled" (see Software Architecture Design Patterns In Java by Partha Kuchana, Auerbach, 2004). In other words, you put the code for the stuff you want to do in a separate object, then call it whenever needed.

For instance, Listing Two(a) illustrates how the commandAction() method might look after applying the Command Pattern. This commandAction() method will never grow due to new commands. A key component here is the AbstractCommand class. It extends Command and is an abstract class that defines the interface (not the Java Interface) that all commands have to use by extending AbstractCommand. Listing Two(b) is the AbstractCommand. As you can see, every command must implement its own execute() method, which is where the action goes. Listing Three illustrates a simple command.

(a)

// Implementation of the CommandListener
public void commandAction(Command command, Displayable d){
   AbstractCommand abstractCommand = (AbstractCommand)command;
   abstractCommand.execute();
}

(b)

public abstract class AbstractCommand extends Command {
   public AbstractCommand(String label, int commandType, int priority) {
      super(label, commandType, priority);
   }
   /* This is where the action goes. */
   public abstract void execute();
}

Listing Two

   
public class MyCommand extends AbstractCommand {
   private TextBox textBox;
   public MyCommand(TextBox t){
      super("Simsalabim", Command.SCREEN, 2);
      textBox = t;
   }
   /* This is where the action is. */
   public void execute() {
      textBox.setString("A rabbit appears");
   }
}

Listing Three

Every command must be configured before it is used. A good place to do this is in the constructor. This lets everything be ready to use as soon as you have an instance of the object. The command in Listing Three is initialized with a TextBox, but it could be anything—adjustable priority, interchangeable canvas, or even different labels for similar commands. It's a bit like the way they use catapults in cartoons. Everything is prepared in advance. Wires are pulled, holders are fastened, and projectiles chosen and carefully inserted. Then it is ready to be used (or "executed") at any time just by pulling a rope. Listing Four(a) shows how you can create and initiate a number of commands in the startApp() method of the MIDlet.

<b>(a)</b>

public void startApp() {
   display = Display.getDisplay(this);
   textbox = new TextBox("Command magic", "Do your magic...", 256, 
      TextField.ANY);
   //Prepare commands
   textbox.addCommand(new ExitCommand(this));
   textbox.addCommand(new MyCommand(textbox));
   textbox.addCommand(new AnotherCommand(textbox));
   textbox.addCommand(new YetAnotherCommand(textbox));
   textbox.setCommandListener(this);
   display.setCurrent(textbox);
}

<b>(b)</b>

public class ExitCommand extends AbstractCommand {
   private MIDlet midlet;
   public ExitCommand(MIDlet m) {
      super("Exit", Command.EXIT, 2);
      midlet = m;
   }
   /* This is where the action is. */
   public void execute() {
      midlet.notifyDestroyed();
   }
}

Listing Four

Of course, you'd have to create the other classes ExitCommand, AnotherCommand, and YetAnotherCommand, too. MIDlet is supplied to the ExitCommand, whereas a TextBox is supplied to the other commands. This is because the ExitCommand must call the notifyDestroyed() method of the MIDlet to initiate its shutdown. Listing Four(b) is what the class looks like.

So different commands can do entirely different things in the execute() method as long as they are properly prepared in the constructor. This is another of the fundamentals behind the Command Pattern. In Pattern lingua: "Concrete Command subclasses specify a receiver-action pair by storing the receiver as an instance variable and by implementing Execute to invoke the request. The receiver has the knowledge required to carry out the request" (Gamma et al.) But now you know what it means. Best of all, you can now reuse the commands with ease on other screens and canvases in the MIDlet.

Threads

A well-known issue with MIDlet programming is that you can't linger in the commandAction() method. For instance, if you check out the CommandListener interface in the Javadocs, you read that the CommandListener method should return immediately. This means that you have to use threads if you do anything that might take time. Luckily, you can use the Command Pattern structure to implement threads in an easy way—just add a class that executes any command in a run() method, and have it implement the Runnable Interface; see Listing Five(a). Then the change to the commandAction() method in Listing Five(b) will have you using threads like never before.

<b>(a)</b>
class CommandExecuter implements Runnable {
   private AbstractCommand command;
   public CommandExecuter(AbstractCommand c) {
      command = c;
   }
   public void run() {
      command.execute();
   }
}

<b>(b) </b>
// Implementation of CommandListener
public void commandAction(Command command, Displayable d){
   Runnable execute =
      new CommandExecuter((AbstractCommand)command);
   new Thread(execute).start();
}
Listing Five

Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.
 

Video