Command pattern
From Wikipedia, the free encyclopedia
In object-oriented programming, the Command pattern is a design pattern in which objects are used to represent actions. A command object encapsulates an action and its parameters.
For example, a printing library might include a PrintJob class. A user would typically create a new PrintJob object, set its properties (the document to be printed, the number of copies, and so on), and finally call a method to send the job to the printer.
In this case, the same functionality could be exposed via a single SendJobToPrinter() procedure with many parameters. As it takes more code to write a command class than to write a procedure, there is often a reason to use a class. There are many possible reasons:
- A command object is convenient temporary storage for procedure parameters. It can be used while assembling the parameters for a function call and allows the command to be set aside for later use.
- A class is a convenient place to collect code and data related to a command. A command object can hold information about the command, such as its name or which user launched it; and answer questions about it, such as how long it will likely take. It also allows the command to be executed some time after it is defined.
- Treating commands as objects enables data structures containing multiple commands. A complex process could be treated as a tree or graph of command objects. A thread pool could maintain a priority queue of command objects consumed by worker threads.
- Treating commands as objects supports undo-able operations, provided that the command objects are stored (for example in a stack).
- The command is a useful abstraction for building generic components, such as a thread pool, that can handle command objects of any type. If a new type of command object is created later, it can work with these generic components automatically. For example, in Java, a generic
ThreadPool
class could have a methodaddTask(Runnable task)
that accepts any object that implements thejava.lang.Runnable
interface(see ThreadPoolExecutor.execute(Runnable task) ).
Contents |
[edit] Uses for the Command pattern
Command objects are useful for implementing:
- Multi-level undo
- If all user actions in a program are implemented as command objects, the program can keep a stack of the most recently executed commands. When the user wants to undo a command, the program simply pops the most recent command object and executes its undo() method.
- Transactional behavior
- Undo is perhaps even more essential when it's called rollback and happens automatically when an operation fails partway through. Installers need this and so do databases. Command objects can also be used to implement two-phase commit.
- Progress bars
- Suppose a program has a sequence of commands that it executes in order. If each command object has a getEstimatedDuration() method, the program can easily estimate the total duration. It can show a progress bar that meaningfully reflects how close the program is to completing all the tasks.
- Wizards
- Often a wizard presents several pages of configuration for a single action that happens only when the user clicks the "Finish" button on the last page. In these cases, a natural way to separate user interface code from application code is to implement the wizard using a command object. The command object is created when the wizard is first displayed. Each wizard page stores its GUI changes in the command object, so the object is populated as the user progresses. "Finish" simply triggers a call to execute(). This way, the command class contains no user interface code.
- GUI buttons and menu items
- In Swing and Borland Delphi programming, an
Action
is a command object. In addition to the ability to perform the desired command, anAction
may have an associated icon, keyboard shortcut, tooltip text, and so on. A toolbar button or menu item component may be completely initialized using only theAction
object. - Thread pools
- A typical, general-purpose thread pool class might have a public
addTask()
method that adds a work item to an internal queue of tasks waiting to be done. It maintains a pool of threads that execute commands from the queue. The items in the queue are command objects. Typically these objects implement a common interface such asjava.lang.Runnable
that allows the thread pool to execute the command even though the thread pool class itself was written without any knowledge of the specific tasks for which it would be used. - Macro recording
- If all user actions are represented by command objects, a program can record a sequence of actions simply by keeping a list of the command objects as they are executed. It can then "play back" the same actions by executing the same command objects again in sequence. If the program embeds a scripting engine, each command object can implement a toScript() method, and user actions can then be easily recorded as scripts.
- Networking
- It is possible to send whole command objects across the network to be executed on the other machines, for example player actions in computer games.
- Parallel Processing
- Where the commands are written as tasks to a shared resource and executed by many threads in parallel (possibly on remote machines -this variant is often referred to as the Master/Worker pattern)
- Mobile Code
- Using languages such as Java where code can be streamed/slurped from one location to another via URLClassloaders and Codebases the commands can enable new behavior to be delivered to remote locations (EJB Command, Master Worker)
[edit] Structure
[edit] Terminology
The terminology used to describe command pattern implementations is not consistent and can therefore be confusing.
- Client, Source: the button, toolbar button, or menu item clicked, the shortcut key pressed by the user.
- Invoker, Command Object, Routed Command Object, Action Object: a singleton object (e.g. there is only one CopyCommand object), which knows about shortcut keys, button images, command text, etc. related to the command. A client/source object calls the Command/Action object's execute/performAction method. The Command/Action object notifies the appropriate client/source objects when the availability of a command/action has changed. This allows buttons and menu items to become inactive (grayed out) when a command/action cannot be executed/performed.
- Receiver, Target Object: the object that is about to be copied, pasted, moved, etc.
- Command Object, routed event args, event object: the object that is passed from the source to the Command/Action object, to the Target object to the code that does the work. Each button click or shortcut key results in a new command/event object. Some implementations add more information to the command/event object as it is being passed from one object (e.g. CopyCommand) to another (e.g. document section). Other implementations put command/event objects in other event objects (like a box inside a bigger box) as they move along the line, to avoid naming conflicts.
- Handler, ExecutedRoutedEventHandler, method, function: the actual code that does the copying, pasting, moving, etc. In some implementations the handler code is part of the command/action object. In other implementations the code is part of the Receiver/Target Object, and in yet other implementations the handler code is kept separate from the other objects.
- Command Manager, Undo Manager, Scheduler, Queue, Dispatcher, Invoker: an object that puts command/event objects on an undo stack or redo stack, or that holds on to command/event objects until other objects are ready to act on them, or that routes the command/event objects to the appropriate receiver/target object or handler code.
[edit] Example (C++)
Consider a simple recipe making program. Every command could be represented as an object. Then if the user makes a mistake then he/she can undo the command by removing that object from the stack
#include <iostream> #include <vector> #include <string> using namespace std; class Command{ public: virtual void execute(void) =0; virtual ~Command(void){}; }; class Ingredient : public Command { public: Ingredient(string amount, string ingredient){ _ingredient = ingredient; _amount = amount; } void execute(void){ cout << " *Add " << _amount << " of " << _ingredient << endl; } private: string _ingredient; string _amount; }; class Step : public Command { public: Step(string action, string time){ _action= action; _time= time; } void execute(void){ cout << " *" << _action << " for " << _time << endl; } private: string _time; string _action; }; class CmdStack{ public: void add(Command *c) { commands.push_back(c); } void createRecipe(void){ for(vector<Command*>::size_type x=0;x<commands.size();x++){ commands[x]->execute(); } } void undo(void){ if(commands.size() > 1) { commands.pop_back(); } else { cout << "Can't undo" << endl; } } private: vector<Command*> commands; }; int main(void) { CmdStack list; cout << "Recipe for simple Fried Rice" << endl; list.add(new Ingredient("2 tablespoons", "vegetable oil")); list.add(new Ingredient("3 cups", "rice")); list.add(new Step("Stir-fry","3-4 minutes")); list.add(new Ingredient("1 bottle","Ketchup")); /*Mistake!*/ list.undo(); list.add(new Ingredient("4 ounces", "peas")); list.add(new Ingredient("1 teaspoon", "soy sauce")); list.createRecipe(); cout << "Enjoy!" << endl; return 0; }
[edit] See also
[edit] References
- Freeman, E; Sierra, K; Bates, B (2004). Head First Design Patterns. O'Reilly.
- GoF - Design Patterns
[edit] External links
- http://c2.com/cgi/wiki?CommandPattern
- http://www.martinfowler.com/eaaCatalog/unitOfWork.html
- http://hatena.dyndns.org/~jkondo/DesignPattern/Command/ (Just Perl source code with no Comments at all)
- http://www.javaworld.com/javaworld/javatips/jw-javatip68.html
- http://www.microsoft.com/belux/msdn/nl/community/columns/jdruyts/wpf_commandpattern.mspx (Windows_Presentation_Foundation)
- Microsoft's Windows Presentation Foundation Commanding OverView
- PerfectJPattern Open Source Project, Provides a componentized i.e. context-free and type-safe implementation of the Command Pattern in Java
- Jt J2EE Pattern Oriented Framework
|