Design patterns: Command

in design-patterns •  6 years ago 

original_child_boss.jpg

Today, the pattern a little more complicated than the previous one, ie the Command pattern, is very similar to the Chain of Responsibility pattern, however, it differs a little, has a very similar purpose as the chain of responsibilities, that is, the transmission of requests, but if necessary can they are still written on the stack in order to eg undo the previously performed operation, more precisely about this pattern further in the article :)


Discussion

The main purpose of this pattern is to encapsulate all data needed to execute the request, usually this data is the object so that the parameters of these requests can be changed depending on the type of recipient, this pattern have also possibility to save the requests on the stack or queue to view the history of these requests or, if necessary, undo these requests.

The most important elements in the implementation of the Command pattern are:

  1. The Command interface that has a defined execute() method.
  2. The ConcreteCommand class that extends the Command interface by extending the execute() method.
  3. The Receiver class, which communicates with the ConcreteCommand class, forwards the client's requests.
  4. The customer who creates the ConcreteCommand class object and sets the Receiver class.

There are many examples where you can use the command pattern :) You can use it as I mentioned earlier in some applications that require viewing history or undoing or adding some action, you can also use it in progress bar, and surely you know to what progress bar is used for :) of course, to review the progress of executing some requests, the command pattern it is also often used to perform actions after clicking on the button, for example. etc etc. :)

As you can see, the uses of the Command pattern are many 🤔 , especially in these large projects.

depressedman.jpg

Intent

  1. Encapsulation the request in the object
  2. Changing the parameters of the request depending on the type of recipient.
  3. The ability to save requests in the queue.

Problem

For example, you must send requests to objects without knowing these requests or objects receiving the request.

Use when:

  1. You need to view the history of requests made or as you need, undo them.
  2. You must encapsulate all the data you want to send.
  3. You must change the parameters of these requests without violating the open-closed principle.


    pensiveman.jpg

Structure

Standard UML diagram of the Command pattern:
Command.png

I do not have to repeat myself, I have already explained what is more or less the implementation in the discussion section at the top.

The CallbackInterface interface is the Command interface and the rest of the classes that expand this interface is ConcreteCommand.

Let’s finally get to the real code 🙂

Example

Switching the lamp

A simple example of turning the lamp on and off so that you can easily understand this pattern

Let’s start with the ICommand interface.

namespace SwitchCommandExample
{
    public interface ICommand
    {
        void Execute();
    }
}

Has a method defined as method Execute(), nothing extraordinary 🙂

Classes that extend the ICommand interface to CloseSwitchCommand and OpenSwitchCommand.

First CloseSwitchCommand.

namespace SwitchCommandExample
{
    public class CloseSwitchCommand : ICommand
    {
        private ISwitchable _switchable;

        public CloseSwitchCommand(ISwitchable switchable)
        {
            _switchable = switchable;
        }

        public void Execute()
        {
            _switchable.PowerOff();
        }
    }
}

And OpenSwitchCommand.

namespace SwitchCommandExample
{
    public class OpenSwitchCommand : ICommand
    {
        private ISwitchable _switchable;

        public OpenSwitchCommand(ISwitchable switchable)
        {
            _switchable = switchable;
        }

        public void Execute()
        {
            _switchable.PowerOn();
        }
    }
}

Also, nothing difficult 🙂 these classes call methods depending on whether we want to turn on the lamp or turn it off.

You can also see the defined ISwitchable interface in these classes so as not to create a specific class type. We remember the dependency inversion principle 🙂

Let’s see what is in the ISwitchable interface.

namespace SwitchCommandExample
{
    public interface ISwitchable
    {
        void PowerOn();
        void PowerOff();
    }
}

Also, nothing difficult 🙂 We have defined methods of turning the lamp on and off 🙂

Let’s go further 🙂 to the Receiver class in our case it’s called Switch.

namespace SwitchCommandExample
{
    public class Switch
    {
        ICommand _closedCommand;
        ICommand _openedCommand;

        public Switch(ICommand closedCommand, ICommand openedCommand)
        {
            _closedCommand = closedCommand;
            _openedCommand = openedCommand;
        }

        public void Close()
        {
            _closedCommand.Execute();
        }

        public void Open()
        {
            _openedCommand.Execute();
        }
    }
}

We see that this class communicates with the CloseSwitchCommand and OpenSwitchCommand classes, which we pass to the constructor and in this way we can call their methods.

And the Light class, which displays the appropriate messages and saves the status of the lamp.

namespace SwitchCommandExample
{
    public class Light : ISwitchable
    {
        bool LightState=false;

        public void PowerOn()
        {
            CheckState(true, "The light is already turned on!", "The light is on");
        }

        public void PowerOff()
        {
            CheckState(false, "The light is already turned off!", "The light is off");
        }

        public void CheckState(bool state, string execption,string notification)
        {
            if (LightState == state)
            {
                Console.WriteLine(execption);
            }
            else
            {
                Console.WriteLine(notification);
                LightState = state;
            }
        }
    }
}

Finally, the customer.

namespace SwitchCommandExample
{
    class Program
    {
        public static void Main(string[] arguments)
        {
            string argument=null;

            ISwitchable lamp = new Light();

            ICommand switchClose = new CloseSwitchCommand(lamp);
            ICommand switchOpen = new OpenSwitchCommand(lamp);

            Switch @switch = new Switch(switchClose, switchOpen);

            while(!string.IsNullOrEmpty(argument =Console.ReadLine()))
            {
                if (argument == "ON")
                {
                    @switch.Open();
                }
                else if (argument == "OFF")
                {
                    @switch.Close();
                }
                else
                {
                    Console.WriteLine("Argument \"ON\" or \"OFF\" is required.");
                }
            }

            Console.ReadKey();
        }
    }
}

In the client, we create objects of these classes and put them in the appropriate constructors of other classes. And we’ll see the appropriate messages depending on what we enter in the console.

Result:

CommandSwitchexample.png

Some of you may ask “Why is it so complicated? Is not it better to do it in this way?”

namespace SwitchSimplerExample
{
    class Program
    {
        static void Main(string[] args)
        {
            string argument = null;

            Light light = new Light();

            while (!string.IsNullOrEmpty(argument = Console.ReadLine()))
            {
                if (argument == "ON")
                {
                    light.PowerOn();
                }
                else if (argument == "OFF")
                {
                    light.PowerOff();
                }
                else
                {
                    Console.WriteLine("Argument \"ON\" or \"OFF\" is required.");
                }
            }

            Console.ReadKey();
        }
    }

    public class Light
    {
        bool LightState = false;

        public void PowerOn()
        {
            CheckState(true, "The light is already turned on!", "The light is on");
        }

        public void PowerOff()
        {
            CheckState(false, "The light is already turned off!", "The light is off");
        }

        public void CheckState(bool state, string execption, string notification)
        {
            if (LightState == state)
            {
                Console.WriteLine(execption);
            }
            else
            {
                Console.WriteLine(notification);
                LightState = state;
            }
        }
    }
}

Well, the main motivation for using the Command pattern is to encapsulate all the data needed to perform the request, in the previous example everything is encapsulated in requests and we have a nicely separate code for sending requests and a code receiving these requests, which gives us a nicer and more flexible code and of course we can monitor demands, but I think that those who do not do major projects should, for now, have this pattern, so to speak “behind the head”. The Command pattern we should use in this bigger projects. In these smaller and medium-sized projects, we should be guided by the KISS principle.

Real-life example

Restaurant – ordering food

Suppose we have to make a system that records all the activities of ordering food from the order by the customer to the order to the cook and we want to be able to see the orders that are in the queue, it is good to use the command pattern in this example. To illustrate the situation is the picture below 🙂
Command_example1.png

We start from the Customer customer class.

namespace Restaurant
{
    class Customer
    {
        IOrder placeorder;

        public Customer(IOrder placeorder)
        {
            this.placeorder = placeorder;
        }

        public void order(string order)
        {
            Console.WriteLine("Client ordered " + order);
            placeorder.PlaceOrder(order);
        }
    }
}

IOrder interface

namespace Restaurant
{
    interface IOrder
    {
        void PlaceOrder(string order);
    }
}

We know the client places the order for the waiter, so we go to the Waiter class.

namespace Restaurant
{
    class Waiter: IOrder
    {
        private ICommand Icommand;

        public Waiter(ICommand Icommand)
        {
            this.Icommand = Icommand;
        }

        public void PlaceOrder(string order)
        {
            Console.WriteLine("Waiter: Send this to a cook");
            Icommand.Execute(order);
        }
    }
}

ICommand interface

namespace Restaurant
{
    interface ICommand
    {
        void Execute(string order);
    }
}

The waiter saves the order, in our case to the Order class.

namespace Restaurant
{
    class Order: ICommand
    {
        private ICookAble Icookcble;

        public Order(ICookAble Icookcble)
        {
            this.Icookcble = Icookcble;
        }

        public void Execute(string order)
        {
            Icookcble.CookTheMeal(order);
        }
    }
}

ICookAble interface

namespace Restaurant
{
    interface ICookAble
    {
        void CookTheMeal(string order);
    }
}

And he hands it over to the cook, in other words the Cook class.

namespace Restaurant
{
    class Cook: ICookAble
    {
        Queue<string> orders = new Queue<string>();

        public void AddOrder(string order)
        {
            orders.Enqueue(order);
        }

        public void CookTheMeal(string order)
        {
            AddOrder(order);
            Console.WriteLine("Cook: Cook the meal number: "+ orders.Count);
        }

        public void DisplayOrders()
        {
            foreach(string o in orders)
            {
                Console.WriteLine(o);
            }
        }
    }
}

Naturally, the waiter gave the order card to the cook, so he can read them all. Of course, all orders are saved in a queue, according to which customer first placed the order 🙂

Beautifully simple and pleasant 🙂

And we create all objects in the Main function.

namespace Restaurant
{
    class Program
    {
        static void Main(string[] args)
        {
            Cook cook = new Cook();

            Order order = new Order(cook);

            Waiter waiter = new Waiter(order);

            Customer customer1 = new Customer(waiter);

            Customer customer2 = new Customer(waiter);

            Customer customer3 = new Customer(waiter);

            customer1.order("Chicken salad, pasta, ice tea, cheese cake");

            Console.WriteLine();

            customer2.order("Vegetables & Tofu");

            Console.WriteLine();

            customer3.order("Chicken, Pork, Beef, Prawn");

            Console.WriteLine("\nList of orders");

            cook.DisplayOrders();

            Console.ReadKey();
        }
    }
}

Result:
CommandRestaurant.png

Relations with other design patterns

The patterns of Chain of Responsibility, Command, Mediator, and Observer describe how you can separate classes that send requests and receive them, but with different compromises 🙂
The Chain of Responsibility pattern can use the Command pattern to represent requests as objects.
Sometimes, some of the actions that we want to write to the history we need to copy, this works like the Prototype pattern.


Summary

That’s all about Command🙂.

Link to github with the whole code from this article: https://github.com/Slaw145/Command

This content also you can find on my blog: http://devman.pl/programtech/designpatterns/design-patterns-command/

And on medium: https://medium.com/@sawomirkowalski/design-patterns-command-dbbe8bd7b02c

In the next article, we will talk about the State pattern.

And NECESSERILY join the DevmanCommunity community on fb, part of the community is in one place 🙂

– site on fb: Devman.pl-Slawomir Kowalski

– group on fb: DevmanCommunity

Ask, comment underneath at the end of the post, share it, rate it, whatever you want🙂.

Illustrations, pictures and diagrams are from: https://sourcemaking.com/design_patterns/command

Authors get paid when people like you upvote their post.
If you enjoyed what you read here, create your account today and start earning FREE STEEM!