Command Design Pattern

My new video on the command design pattern is online at:

Introduction

Any object oriented software operates on interaction of various software components called objects. A typical interaction between two objects is a “client-server” interaction where one object sends a request and the other object processes the request and returns a response. The command design pattern provides a way for the client to encapsulate each request as an object (command) and submit each such request object to a another object called the invoker.

Key Features of the Command Design Pattern:

  1. All the invoker knows is that it holds a collection of commands and it can execute those commands immediately or later. Also, the invoker does not know the details of what each command does.
  2. Since all commands implement a common interface, the invoker can execute those via the common interface and that way its not coupled to any concrete command and the details of what each command does.
  3. Another key player in this type of interaction is the receiver object. Each command encapsulates its receiver object. And there can be more than one receiver involved in the command pattern object interaction if necessary.
  4. A command is initiated by the invoker object but it is the receiver object that eventually processes the command.
  5. A command object is self-contained – it knows its receiver and all the data that is needed to execute that command. So a command can be persisted in a  “queue” and executed later.

So one advantage of using command pattern is that creation of commands is independent of when it is executed. Also, the commands can be grouped in multiple groups and executed in a batch like a macro. So if we were implementing an airplane’s navigation system, all the commands for a plane to depart (taxi to runway, takeoff, adjust altitude and speed to go up to 10000 feet) and arrive (reduce speed and altitude to be able to land, land and taxi to gate) can be two sets of commands. Each set is basically like a macro and can be executed at different points of time by the invoker which is the cockpit dashboard. Another advantage of the command design pattern is that the commands can be executed as a transaction where either all commands are executed or none of these are executed. In such as case, the command interface could provide two stubs – execute and undo. The ‘undo’ operation would reverse all the actions of a command. So if the invoker encounters an error, it would execute undo operation on all commands executed to that point and this will essentially be an “all or nothing” transnational operation.

The video link at the beginning of this post includes all the details of the command design pattern with an implementation of a logging framework. The source code is provided below.

Abstract Command:

//common contract for all logger commands
//this is the abstract command
public interface ILogMessageCommand
{
  void LogMessage();
}

Concrete Command for File Logging:

//concrete command
public class LogMessagetoFileCommand: ILogMessageCommand
{
//receiver
FileLog _fileLog = null;
//the message to be logged
String _message = null;
 
public LogMessagetoFileCommand(FileLog filelog, String message)
{
_fileLog = filelog;
_message = message;
}
 
public void LogMessage()
{
//interact with the receiver to process the command
_fileLog.LogMessage(_message);
}
 
}

Concrete Command for Database Logging:

public class LogMessagetoDatabaseCommand : ILogMessageCommand
{
   DatabaseLog _dbLog = null; //receiver
   String _message = null; //the message to be logged
 
  public LogMessagetoDatabaseCommand(DatabaseLog dblog, 
          String message)
   {
    _dbLog = dblog;
    _message = message;
   }
 
public void LogMessage()
   {
   //interact with the receiver to process the command
    _dbLog.LogMessage(_message);
   }
}

FileLog Receiver:

public class FileLog
{
   //singleton instance
   public static readonly FileLog Instance = new FileLog();
  //constructor should be private for singleton implementation
    private FileLog()
    {
    }
   //read the log file path from the application configuration file
    String _filePath = 
    ConfigurationManager.AppSettings["LogFilePath"].ToString();
   //write the log message to the file
   public void LogMessage(String message)
   {
    Console.WriteLine("Writing to a log file");
    string[] AllMessages = new string[] {message};
    File.WriteAllLines(_filePath, AllMessages);
   }
}

Database Log Receiver:

public class DatabaseLog
   {
    //singleton instance
     public static readonly DatabaseLog Instance 
     = new DatabaseLog();
   //constructor should be private for singleton implementation
    private DatabaseLog()
    {
    }
//read the connection string from the application configuration file
   String _connectionString 
   = ConfigurationManager.ConnectionStrings["LogDatabase"].ToString();
 
    //log the message to a database table
    //not implemented yet
   public void LogMessage(String message)
   {
     Console.WriteLine("Writing to a logging database");
     try
     {
      IDbConnection Conn = new SqlConnection(_connectionString);
      IDbCommand Cmd = new SqlCommand();
      Cmd.CommandType = CommandType.StoredProcedure;
      //stored procedure name for logging
      Cmd.CommandText = "usp_AddText";
 
      Cmd.Parameters.Add(new SqlParameter("@message", message)); 
     //Conn.Open();
     //Cmd.ExecuteNonQuery(); not implemented
     //Conn.Close();
     }
    catch (Exception ex)
     {
     //TODO: handle exception
     }
   }
}

Invoker:

public class LoggerFramework
{
   List _allCommands = null;
 
   //receive all commands
   public LoggerFramework(List allCommands)
    {
     _allCommands = allCommands;
    }
 
   //invoker them one by one
   //does not know concrete commands
   public void LogMessages()
   {
    foreach (ILogMessageCommand command in _allCommands)
    {
     command.LogMessage();
    }
  }
}

Invoker:

public class LoggerFramework
{
   List _allCommands = null;</code>
 
   //receive all commands
   public LoggerFramework(List allCommands)
   {
    _allCommands = allCommands;
   }
 
   //invoker them one by one
   //does not know concrete commands
    public void LogMessages()
    {
     foreach (ILogMessageCommand command in _allCommands)
    {
      command.LogMessage();
    }
  }
}

Client:

//create concrete command objects
//create log message to file command 
//and set the receiver and the message on it
ILogMessageCommand LogMessageToFileCommand = 
new LogMessagetoFileCommand(FileLog.Instance, "Message for file");
//create log message to database command and 
//set the receiver and the message on it
ILogMessageCommand LogMessagetoDbCommand = 
new LogMessagetoDatabaseCommand(DatabaseLog.Instance, 
"Message for database");
 
//create a list of commands
List _allCommands = new List();
_allCommands.Add(LogMessageToFileCommand);
_allCommands.Add(LogMessagetoDbCommand);
 
//create the invoker and set the commands on it
LoggerFramework framework = new LoggerFramework(_allCommands);
//request the invoker to execute all commands
framework.LogMessages();
 
//display a message for the user so thay can quit the program
Console.WriteLine("Press any key to quit.");
 
//wait for user input before console window is closed
Console.ReadKey();

Sorry this turned out to be a long post partly due to the inclusion of the source code. I’d love to hear from you how you have implemented the command design pattern. Any other feedback is always appreciated.

4 thoughts on “Command Design Pattern”

    1. Thanks. Appreciate your feedback. I am trying to create videos and blogs on several topics of interest. If you’d like me to cover a specific topic or have a question about a post, please feel free to post a question or comment.

Leave a Reply

Your email address will not be published. Required fields are marked *