How to Implement Command Design Pattern in C#

command design pattern

The Command design pattern is an important thing in C#, primarily when we need to slow down a request’s execution. 

We can also keep track of our operator with its help. The ability to keep track of our activities helps us to change them whenever we like. 

For more information, let’s plunge into this segment to provide you a thorough process by which you can use command design pattern in c#.

Application of Command Design Pattern

The Command design pattern is made up of Invoker class, Command class/interface, Concrete command classes and the Receiver class. We are going to follow the same pattern in the examples. 

The thing we will do is to write a simple app. By using the Command design pattern we can change the cost of the object.

So, let’s begin with the receiver class, which contains the base business logic in our app.

public class Product

{

    public string Name { get; set; }

    public int Price { get; set; }

    public Product(string name, int price)

    {

        Name = name;

        Price = price;

    }

    public void IncreasePrice(int amount)

    {

        Price += amount;

        Console.WriteLine($”The price for the {Name} has been increased by {amount}$.”);

    }

    public void DecreasePrice(int amount)

    {

        if(amount < Price)

        {

            Price -= amount;

            Console.WriteLine($”The price for the {Name} has been decreased by {amount}$.”);

        }

    }

    public override string ToString() => $”Current price for the {Name} product is {Price}$.”;

}

This is the receiver class.The logic is quite straightforward.We have to only conditionally increase or decrease the product’s price. We can also use ToString method which will help to print the object.

Also, this Client class can embody the product class and move the needed action forward. However, the Command design pattern gives clear instruction to not use the receiver class directly. Rather, we should obtain all the demand in a special class-Command. 

At first we will add the ICommand interface:

Public interface ICommand

{

       Void ExecuteAction();

}

To calculate the price modification actions, we will add a simple PriceAction enumeration:

Public enum PriceAction

{

         Increase

         Decrease

}

Lastly we will add the ProductCommand class:

public class ProductCommand : ICommand

{

    private readonly Product _product;

    private readonly PriceAction _priceAction;

    private readonly int _amount;

    public ProductCommand(Product product, PriceAction priceAction, int amount)

    {

        _product = product;

        _priceAction = priceAction;

        _amount = amount;

    }

    public void ExecuteAction()

    {

        if(_priceAction == PriceAction.Increase)

        {

            _product.IncreasePrice(_amount);

        }

        else

        {

            DecreasePrice(_amount);

        }

    }

}

It can be seen that the ProducCommand class consists of all the information regarding the demands and thus the action is executed accordingly.

Let’s move on to the next part. We have to add ModifyPrice class, that will act as Invoker:

public class ModifyPrice

{

    private readonly List<IProductCommand> _commands;

    private ICommand _command;

    public ModifyPrice()

    {

        _commands = new List<ICommand>();

    }

    public void SetCommand(ICommand command) => _command = command;

    public void Invoke()

    {

        _commands.Add(_command);

        _command.ExecuteAction();

    }

}

This class will work with the command which will implement the ICommand interface and store all the operations as well.

Let’s get to the client part now:

class Program

{

    static void Main(string[] args)

    {

        var modifyPrice = new ModifyPrice();

        var product = new Product(“Phone”, 500);

        Execute(product, modifyPrice, new ProductCommand(product, PriceAction.Increase, 100));

        Execute(product, modifyPrice, new ProductCommand(product, PriceAction.Increase, 50));

        Execute(product, modifyPrice, new ProductCommand(product, PriceAction.Decrease, 25));

        Console.WriteLine(product);

    }

    private static void Execute(Product product, ModifyPrice modifyPrice, ICommand productCommand)

    {

        modifyPrice.SetCommand(productCommand);

        modifyPrice.Invoke();

    }

}

The result of this is shown below:

The price for the Phone has been increased by 100$.

The price for the Phone has been increased by 50$.

The price for the Phone has been decreased by 25$.

Current price for the Phone product is 625 $.

Press any key to continue . . .

Good. After the modification, we will now see the order of our actions. 

We can track our actions in the Invoker class. There are many benefits of using the Invoker class, one such benefit is that we can undo our operations if we want to.

So, let’s give it a try.

To Carry Out the Undo Operation Using Command Design Pattern

To put in effect the Undo operation, let’s begin with the ICommand interface modification:

Public interface ICommand 

{

       void ExecuteAction();

       Void UndoAction();

}

After that, we have to modify the ProductCommand class by adding the UndoAction method:

Public void UndoAction()

{

        If (_priceAction == PriceAction.Increase)

        }   

        else

        {      

              _product.IncreasePrice(_amount);

        }

}         

We definitely have to modify the ModifyPrice class and also by adding the UndoAction method:

Public void UndoActions()

{

        foreach (var command in Enumerable.Reverse(_commands

        {

               command.UndoAction();

         }

}

You should note that we are not implementing the Linq Reverse method, but the Enumerable.Reverse (). We do not use Linq method because it will cause the list to mutate, and we don’t want that to happen. We just want to reverse the list without mutating it.

The Client class calls the UndoActions method which will emphasize on the operations on list, and therefore will carry out the operations different from what was required earlier.

Let’s have a look:

class Program

{

    static void Main(string[] args)

    {

        var modifyPrice = new ModifyPrice();

        var product = new Product(“Phone”, 500);

        Execute(product, modifyPrice, new ProductCommand(product, PriceAction.Increase, 100));

        Execute(product, modifyPrice, new ProductCommand(product, PriceAction.Increase, 50));

        Execute(product, modifyPrice, new ProductCommand(product, PriceAction.Decrease, 25));

        Console.WriteLine(product);

        Console.WriteLine();

        modifyPrice.UndoActions();

        Console.WriteLine(product);

    }

    private static void Execute(Product product, ModifyPrice modifyPrice, ICommand productCommand)

    {

modifyPrice.SetCommand(productCommand);

        modifyPrice.Invoke();

    }

}

The result will be as follows:-

The price for the Phone has been increased by 100$.

The price for the Phone has been increased by 50$.

The price for the Phone has been decreased by 25$.

Current price for the Phone Product is 625$.

The price for the Phone has been increased by 25$.

The price for the Phone has been decreased by 50$.

The price for the Phone has been decreased by 100$.

Current price for the Phone product is 500$.

Press any key to continue . . .

After this everything will work as it was supposed to.

Improving the Solution

Command design pattern is used in our apps, and nothing is bad about it. However, there is a minor fault in our solution which is not linked to the Command pattern but with the overall business logic.  

So what should be done to change a less amount like 25 to 2500?Well, a protection is available for the DecreasePrice method, and it will not alter the outcome. However, it will influence the Undo actions. 

Let’s have a look:

Execute(product, modifyPrice, new ProductCommand(product, PriceAction.Decrease, 2500));

…           

The result will look like this:

The price for the Phone has been increased by 100$.

The price for the Phone has been increased by 50$.

Current price for the Phone product is 650$.

The price for the Phone has been increased by 2500$.

The price for the Phone has been decreased by 50$. 

The price for the Phone has been decreased by 100$.

Current price for the phone Phone product is 3000$.

Press any key to continue . . .

As you can see, the price is not reduced, however, the operation is preserved within the store, which made the Undo action to fail. 

Let’s now fix this:

At first we have to modify the DecreasePrice method within the Product class.

public bool DecreasePrice(int amount)

{

    if(amount < Price)

    {

        Price -= amount;

        Console.WriteLine($”The price for the {Name} has been decreased by {amount}$.”);

        return true;

    }

    return false;

}

We can also customize the ProductCommand class also:

public class ProductCommand : ICommand

{

    private readonly Product _product;

    private readonly PriceAction _priceAction;

    private readonly int _amount;

    public bool IsCommandExecuted { get; private set; }

    public ProductCommand(Product product, PriceAction priceAction, int amount)

    {

        _product = product;

        _priceAction = priceAction;

        _amount = amount;

    }

    public void ExecuteAction()

    {

        if(_priceAction == PriceAction.Increase)

        {

            _product.IncreasePrice(_amount);

            IsCommandExecuted = true;

        }

        else

        {

            IsCommandExecuted = _product.DecreasePrice(_amount);

        }

    }

    public void UndoAction()

    {

        if (!IsCommandExecuted)

            return;

        if (_priceAction == PriceAction.Increase)

        {

            _product.DecreasePrice(_amount);

        }

        else

        {

            _product.IncreasePrice(_amount);

        }

    }

}

This is the end of the process. If we begin the app with a smaller quantity of 2500, the result will be correct.

The price for the Phone has been increased by 100$.

The price for the Phone has been increased by 50$.

Current price for the Phone product is 650$.

The price for the Phone has been decreased by 50$.

The price for the Phone has been decreased by 100$.

Current price for the phone product is 500$.

Press any key to continue . . .

This completes the whole process.

Summing Up

Though the Command design pattern are very complex, it is very useful.

With the help of Command design pattern, we can decouple classes that requires assistance from the classes and execute these operations as well.

In addition, to apply new command, we do not have to alter the current classes. Hence you can use these command classes in your project. 

Posted in c#

Next Post

Julia vs. Python: The Superior Option for Data Science

Sat Aug 31 , 2019
Among many uses of Python Language, data analytics has become the most significant one. The Python consists of libraries, applications, and tools that make the process of data analysis and scientific computing very fast and smooth. However, the Julia Language was aimed specifically for doing machine learning, large-scale linear algebra, […]

You May Like