Design Patterns - Command

10 juni 2022 om 10:00 by ParTech Media - Post a comment

In our previous blog of the design pattern series, we had discussed the chain of responsibility design pattern, which falls under the category of behavioral design patterns. Today, we will explore another design pattern from the same category called Command Design Pattern.

Table of contents

  1. Introduction to Command design pattern,
  2. Implementation of Command design pattern
  3. Conclusion

Introduction to Command design pattern

The Command design pattern encapsulates the actual object which performs the action by introducing classes and objects between the client and the actual class, which has the logic to execute.

Command design pattern comes in handy when we need to change the parameters based on the action that needs to be carried out. For instance:

  • When there is a need to de-couple the actual work-performing class from the client.
  • When there is a need to implement rollback, logging, and transaction logic.
  • When there is a need to create and execute the requests based on different conditions or when there is a need to execute at a different time.
  • When there is a need to implement undo and redo functionality.

Implementation of Command design pattern

The command design pattern mainly consists of:

  1. Command
  2. ConcreteCommand
  3. Invoker
  4. Receiver

Here is a template that we can use to show its implementation -

using System;

namespace PARTECH_Command
{
    internal class Program
    {
        static void Main(string[] args)
        {
            var invoker = new Invoker();
            var receiver = new Receiver();
            var command = new ConcreteCommand(receiver);
            invoker.command = command;
            invoker.ExecuteCommand();
            Console.ReadLine();
        }
    }

    public class Receiver
    {
        public void DoAction(string inputClass)
        {
            Console.WriteLine($"Receiver method called from class - {inputClass}");
        }
    }

    public interface ICommand
    {
        void DoAction();
    }

    public class ConcreteCommand: ICommand
    {
        public Receiver _receviver;

        public ConcreteCommand(Receiver receiver)
        {
            _receviver = receiver;
        }

        public void DoAction()
        {
            _receviver.DoAction("Concrete Command");
        }
    }

    public class Invoker
    {
        public ICommand command;

        public void ExecuteCommand()
        {
            command.DoAction();
        }
    }
}

Here, The receiver is the class that performs the actual request.

ICommand is the interface that has the method’s signature.

ConcreteCommand is the class that implements the interface ICommand and has a public property to hold the receiver object. And it also implements the method from the ICommand interface. Inside that, it calls the method of the receiver class, which handles the request.

Invoker is the class that is operated by the client. It has a public object to hold the ICommand and a method to call another method that is inside the ICommand object.

In the client method, which is the main method here, new objects for the invoker and receiver are created first. A concrete command object is created by passing the receiver object to it. This is then assigned to the invoker. After this, the invoker calls the execute method. This calls the concrete command, which, in turn, calls the receiver.

On executing the above template code, the below output gets generated.

Now that we have understood the basic template to implement the Command design pattern let us implement the same through a practical scenario.

In most server-based applications, the data is stored in the database in the form of tables. And there will be multiple queries or stored procedures accessed by the application to perform some operation using the stored data. To do this, a connection to the database has to be opened every time. Then the query/stored procedure has to be executed. Finally, the database connection has to be closed. Since the connections are left open, the application might not get new connections to execute the queries. This will result in application erroring.

Let us implement this scenario using the Command design pattern.

using System;

namespace PARTECH_Command
{
    internal class Program
    {
        static void Main(string[] args)
        {
            Database database = new Database();
            ICommand openConnection = new CreateConnection(database);
            ICommand executeCommand = new ExecuteQuery(database);
            ICommand closeConnection = new CloseConnection(database);
            DatabaseOperation operation = new DatabaseOperation();

            operation.getConnection = openConnection;
            operation.executeQuery = executeCommand;
            operation.closeConnection = closeConnection;

            operation.GetDbConnection();
            operation.ExecuteQuery();
            operation.CloseConnection();
            Console.ReadLine();
        }
    }

    public class Database
    {
        public void GetConnection()
        {
            Console.WriteLine("Connection to Database Established.");
        }
        public void ExecuteQuery()
        {
            Console.WriteLine("Executing the provided query in the database.");
        }
        public void CloseConnection()
        {
            Console.WriteLine("Connection to Database has been closed.");
        }
    }

    public interface ICommand
    {
        void ExecuteCommand();
    }

    public class CreateConnection : ICommand
    {
        public Database _database;

        public CreateConnection(Database database)
        {
            _database = database;
        }
        public void ExecuteCommand()
        {
            _database.GetConnection();
        }
    }

    public class ExecuteQuery : ICommand
    {
        public Database _database;

        public ExecuteQuery(Database database)
        {
            _database = database;
        }
        public void ExecuteCommand()
        {
            _database.ExecuteQuery();
        }
    }

    public class CloseConnection : ICommand
    {
        public Database _database;

        public CloseConnection(Database database)
        {
            _database = database;
        }
        public void ExecuteCommand()
        {
            _database.CloseConnection();
        }
    }

    public class DatabaseOperation
    {
        public ICommand getConnection;
        public ICommand executeQuery;
        public ICommand closeConnection;

        

        public void GetDbConnection()
        {
            getConnection.ExecuteCommand();
        }

        public void ExecuteQuery()
        {
            executeQuery.ExecuteCommand();
        }

        public void CloseConnection()
        {
            closeConnection.ExecuteCommand();
        }

    }
}

In the above code, the Database class is the receiver that executes the requests for the invoker. In this example, the receiver has three operations: Getting the database connection, executing the query, and closing the database connection. For simple understanding, we have hardcoded the details in each method.

ICommand is the interface that has the signature for the code implementation. CreateCommand, ExecuteQuery, and CloseConnection are the concrete command classes that have the implementation of the ICommand interface. Each of them has a public property of type Database (Receiver), which is used in the respective classes. This is then used to call the respective operation in the ExecuteCommand method.

For example, CreateCommand will have the GetConnection method called in the ExecuteCommand method. The ExecuteQuery method calls Execute query of the database receiver. The CloseConnection calls the CloseConection method of the database class (that is called).

DatabaseOperation is the invoker class that has three properties to hold the objects of CreateCommand, ExecuteQuery, and CloseConnection concrete component classes. The invoker class internally calls the three methods when the client requests to perform the operation. The main method is the client here, which makes the code create an object for the Database (Receiver) and three concrete components. It also has the code to create the object for the invoker. The objects of the concrete components are assigned to the properties of it. Finally, the operations are called one after the other.

On executing the above code, the below output gets printed on the output window.

Conclusion

And that’s what a Command Behavioral design pattern is all about. In this post, we have also seen how to implement it in a real-world scenario. Stay tuned for the next blog on the Design Patterns series.

Nieuwste