Overview:-
An object encapsulates everything needed to execute a method in another object.The command design pattern evaluates the request,instantiates and returns an appropriate concrete object of some general abstract class type,and then polymorphicly calls inherited methods on that concrete object to carry out the business of the class.Thus,each business request from a client object can be handled by a seperate highly encapsulated and loosely coupled object.
Wikipedia Says:-
Command object is a design pattern in which objects are used to represent actions.A command object encapsulates an action and its parameters.
Intent:
a) Encapsulates a request as an object thereby letting you parameterize clients with different requests,queue or log requests and support undoable operations.[GoF,p233]
b) Promote "invocation of a method on an object" to full object status.
c) An object-oriented callback.
Problem:
When two objects communicate,often one object is sending a command to the other object to perform a particular function.The most common way to accompolish this is for the first object(the "issuer") to hold a reference to the second("the reciptant").The issuer executes a specific method on the recipient to send the command.But what if the issuer is not aware of,or does not care who the recepitant is? That is the issuer wants to abstractly issue the command?
The command design pattern encapsulates the concept of the command into an object.The issuer holds a reference to the command object rather than to the reciptant.The isser sends the command to the command object by executing a specific method on it.The command object is then responsible for dispatching the command to a specific to get the job done.
Please note the similarities between Command and Strategy Design Pattern.
Need to issue requests to objects without knowing anything about the operation being requested or the receiver of the request.
Structure Summary:
1) Define a class that maintains a pointer to an object,a pointer to a member function,and all necessary function arguments.
2) Promote "execution of a method on an object" to full object status so that it can be decoupled,queued,unqueued or redone.
Discussion:
Command decouples the object that invokes the operation from the one that knows how to perform it.To achieve this seperation,the designer creates an abstract base class that maps a receiver(an object) with an action( a pointer to a member function).The base class contains the execute() method that simply calls the action on the receiver.
All clients of Command objects treat object as a "black box" by simply invoking the object's virtual execute method whenever the client requires the object's "service".
Actually command class holds some subset of the following: an object,a method to be applied on the object,and the arguments to be passed when the method is applied.The Command's "execute" method then causes the pieces to come together.
Structure:
The client that creates a command is not the same client that executes it.This seperation provides flexibility in the timing and sequencing of commands.Materializing commands as objects means they can be passed,staged,shared,loaded in a table and otherwise intrumented or manipulated like any other object[Grand,p279]
Command objects can be thought of as "tokens" that are created by one client that knows what need to be done,and passed to another client that has the resources for doing it.
Example:
Command pattern allows requests to be encapsulated as objects,thereby allowing clients to be parameterized with different requests."The check at the diner is an example of a command pattern".The waiter or waitress takes an order or command from a customer and encapsulates that order by writing it on the check.Thr order is then queued for a short order cook. Note that the pad of "checks" used by each waiter is not dependent on the menu, and therefore they can support commands to cook many different items. [Michael Duell, "Non-software examples of software design patterns", Object Magazine, Jul 97, p54]
Checklist:
1) Define a Command interface with a method signature like execute().
2) Create one or more derived classes that encapsulate some subset of the following: a "receiver" object,the method to invoke,the arguments to pass.
3) Instantiate a command object for each deferred execution request.
4) Pass the command object from the creator(aka sender) to the invoker(receiver).
5) Invoker decides when to execute().
Rules of thumb
Chain of responsibility,Command,Mediator and Observer,address how you can de-couple senders and receivers,butwith diff trade-offs.Command normally specifies a sender-receiver connection with a subclass.
Chain of responsibility can use command to represent requests as objects.[GoF,p349]
Command can use Memento to maintain the state required for an undo-operation.[GoF, p242]
Command and Memento act as magic tokens to be passed around and invoked at a later time.In command,the token represents a request,in Memento,it represents the internal state of an object at a particular time.Polymorphism is important to Command,but not to Memento because its interface is so narrow that a memento can only be passed as a value.[GoF,p346]
Two important aspects of the command pattern: interface seperation(invoker is isolated from the receiver),time seperation(stores a ready-to-go processing request that's to be stated later.)[Alexandrescu, p101]
A commmand that must be copied before being placed on a history list acts as a Prototype.[GoF,p242]
Uses for the Command Pattern:
a) 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 the undo() method.
b) 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
c) 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.
A command pattern is also known as action or transaction pattern.
Another Example:
Another simple example of a common problem the command design pattern is well suited to solve is the evalution and execution of an incoming HttpServletRequest action parameter command from a submit on a jsp page.
We have 3 ways of accomplishing the same goal.
-> Command Parameter Request Handling: Implementing code with conditional statement activated by the action parameter.
-> Replacing Conditional Logic with objects: Calling out to service objects to execute code specific to the conditional statement activated by the action parameter.
-> Implementing The command Design Pattern: Direct Instantiation and polymorphic implementation of an object without conditional parameters.
Common Parameter Request Handling
private void performTask1(String action) {
//-- Stuffs all business logic into the conditional statements
if( action.equalsIgnoreCase("create") ) {
........
} else if( action.equalsIgnoreCase("replace") ) {
........
} else if( action.equalsIgnoreCase("update") ) {
........
} else if( action.equalsIgnoreCase("delete") ) {
........
} //endif
} //endmethod: performTask1
The performTask1() method evaluates the action parameter in its conditional statements.
Replacing Conditional Logic With Objects:-
This leads us to our first refactoring of this example, the performTask2() method.
private void performTask2(String action) {
//-- Abstracts out all business logic into separate classes
ActionType cmd = null;
if( action.equalsIgnoreCase("create") ) {
cmd = new ActionTypeCreate();
} else if( action.equalsIgnoreCase("replace") ) {
cmd = new ActionTypeReplace();
} else if( action.equalsIgnoreCase("update") ) {
cmd = new ActionTypeUpdate();
} else if( action.equalsIgnoreCase("delete") ) {
cmd = new ActionTypeDelete();
} //endif
cmd.execute();
}
This considerably cleans up the code in the performTask() method of the servlet.
Implementing The Command Design Pattern:-
Here is the performTask() method of a servlet that uses the Command Design Pattern:
private void performTask3(String action) {
ActionType cmd = (ActionType)commandMap.get(action);
cmd.execute();
}
Inorder to facillitate this simple pattern,following code is inserted at the top of the servlet and executed in either the constructor or an init method as shown.
class ExampleServlet {
private HashMap commandMap = new HashMap();
public ExampleServlet() {
commandMap.put("create", new ActionTypeCreate());
commandMap.put("replace", new ActionTypeReplace());
commandMap.put("update", new ActionTypeUpdate());
commandMap.put("delete", new ActionTypeDelete());
}
private void performTask3(String action) {
ActionType cmd = (ActionType)commandMap.get(action);
cmd.execute();
}
}
This servlet may have been instantiated from the ControllerServlet after the controller determined that the request was a database operation-which could have in turn been determined via a Command Design Pattern there as well.Each class does only one thing keeping everything very simple,i.e loosely coupled and highly cohensive(encapsulated).
Finally Below example Simulates a servlet in an M-V-C Model 2 environment.
import java.util.HashMap;
//************************************************************************
/**
* CommandDesignPattern.java
*
* Simulates a servlet in an M-V-C Model 2 environment.
*
* @param action the desired action the servlet is to perform.
*/
public class CommandDesignPattern {
private HashMap commandMap=new HashMap();
public CommandDesignPattern() {
// -- Initialize HashMap of possible ActionType concrete objects
commandMap.put("create",new ActionTypeCreate());
commandMap.put("replace",new ActionTypeCreate());
commandMap.put("update",new ActionTypeCreate());
commandMap.put("delete",new ActionTypeCreate());
}
public void doPost(int approachSolution, String action) {
switch (approachSolution) {
case 1:
//...
performTask1(action);
break;
case 2:
// ....
performTask2(action);
break;
case 3:
performTask3(action);
break;
}
}
public void performTask1(String action) {
if(action.equalsIgnoreCase("create")) {
//...
}else if(action.equalsIgnoreCase("replace")) {
// ...
}else if(action.equalsIgnoreCase("update")) {
//...
}else if(action.equalsIgnoreCase("delete")) {
//...
}
}
public void performTask2(String action) {
ActionType cmd = null;
if( action.equalsIgnoreCase("create") ) {
cmd = new ActionTypeCreate();
} else if( action.equalsIgnoreCase("replace") ) {
cmd = new ActionTypeReplace();
} else if( action.equalsIgnoreCase("update") ) {
cmd = new ActionTypeUpdate();
} else if( action.equalsIgnoreCase("delete") ) {
cmd = new ActionTypeDelete();
} //endif
cmd.execute();
}
public void performTask3(String action) {
ActionType cmd=(ActionType)commandMap.get(action);
cmd.execute();
}
abstract class ActionType {
abstract void execute();
}
class ActionTypeReplace extends ActionType {
public void execute() {
//.....
}
}
class ActionTypeCreate extends ActionType {
public void execute() {
//.....
}
}
class ActionTypeUpdate extends ActionType {
public void execute() {
//.....
}
}
class ActionTypeDelete extends ActionType {
public void execute() {
//.....
}
}
Hope this explanation helps if any.
8 comments:
Hey Prashant,
Very nice explanation of the Command pattern.
I will definitely revisit your blogs.
Thanks for the article.
-Chandan Joarder
Prashant,
It's really nice to read your explanation about patterns.
It will be more useful if the examples are extracted from existing frameworks, rather than creating new ones.
Chandan & Praveena Manvi,
Thanks a lot for your inspiring comments.Frankly content of my articles are taken inspiration from many other articles/links/sites/books etc.
However said that i will surely try to improve further.
Thanks
Prashant
Good one Prashant,
Keep posting such articles.
Thanks
Thanks a lot Amit.
Nice work Prashant,
This was exactly what i needed to get a grip on command pattern.
Thanks for the article.
Thanks Prashant Khanal.
The part of using the map and call the execute method is pretty straight forward. The question I have is how, where and at what stage do you pass the information needed to execute the command. For example, I am creating a new profile how do I pass the profile information to the ActionTypeCreate command.
Post a Comment