Introduction

The command design pattern is a behavioural design pattern in which a request can be turned to action.

Where to use a command design pattern?

When we need to
  • Do/undo action
  • When you want pass method as an argument or when you want to call a call back function
  • When we want to log or track commands

Why use a command design pattern?

Command Design Pattern is a request-driven design pattern. A request will help choose which command needs to be executed without knowing which object.method to call. In this kind of case command, the design pattern plays a key role, making this easy by using ICommand. The command design pattern actually decouples command manager and command execution logic i.e. Actual implementation.
Players in this pattern
  • ICommand – its interface which will do action undo action
  • ConcreateCommand – the one who implements ICommand
  • Invoker – One who carries out the action
  • Receiver: One who receives action from invoker and performs action
Example
Problem definition - Provide an interface to the user to open and close the door. If the user wants, they should be able to undo his/her last action.
This example actually showcases the use case of the do and undo action requirement. For other requirements, I will write separate articles.
Players here
  • ICommand – ICommand
  • ConcreateCommand – DoorCommand
  • Invoker – client, in our case we will client operation in main(home class) function
  • Receiver – Door
We will create an enum for performing the actions:
  1. from enum import Enum
  2. class Action(Enum):
  3. DOOR_OPEN = 0,
  4. DOOR_CLOSE = 1
Below is the Command abstract class which will define the contact to implement:
  1. from abc import ABC, abstractmethod
  2. from actions import Action
  3. class Command(ABC):
  4. @abstractmethod
  5. def execute(self, action: Action):
  6. pass
  7. @abstractmethod
  8. def unDoExecute(self, action: Action):
  9. pass
Below is the DoorCommand class which implements the ICommand contract:
  1. from iCommand import Command
  2. from actions import Action
  3. from door import Door
  4. class DoorCommand(Command):
  5. def __init__(self):
  6. self.door = Door()
  7. def execute(self, action: Action):
  8. switcher = {Action.DOOR_OPEN: self.door.open, Action.DOOR_CLOSE: self.door.close}
  9. self.lastAction = action
  10. # Get the function object from switcher dictionary
  11. function = switcher.get(action, None)
  12. # Execute the function
  13. function()
  14. def unDoExecute(self):
  15. switcher = {Action.DOOR_OPEN: self.door.close, Action.DOOR_CLOSE: self.door.open}
  16. # Get the function object from switcher dictionary
  17. function = switcher.get(self.lastAction, None)
  18. # Execute the function
  19. function()
Below is the Door class, it actually has core logic implementation:
  1. class Door :
  2. def open(self):
  3. print("------------Door Opened---------------")
  4. def close(self) :
  5. print("------------Door Closed---------------")
Below is the Invoker, w hich requests an action
  1. from iCommand import Command
  2. from doorCommand import DoorCommand
  3. from actions import Action
  4. if __name__ == "__main__":
  5. command: Command = DoorCommand()
  6. command.execute(Action.DOOR_OPEN)
  7. command.execute(Action.DOOR_CLOSE)
  8. command.unDoExecute()
Below is the output window
Command Design Pattern Using Python Sample

Summary

In this article, we learned about the usage of a command design pattern, mainly concentrating on the do and undo operation.