Command Design Pattern using Python Sample

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.   
  3. class Action(Enum):  
  4.     DOOR_OPEN = 0,  
  5.     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.   
  4.   
  5. class Command(ABC):  
  6.  
  7.     @abstractmethod  
  8.     def execute(self, action: Action):  
  9.         pass  
  10.  
  11.     @abstractmethod  
  12.     def unDoExecute(self, action: Action):  
  13.         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.   
  5. class DoorCommand(Command):  
  6.   
  7.     def __init__(self):  
  8.         self.door = Door()  
  9.   
  10.     def execute(self, action: Action):  
  11.         switcher = {Action.DOOR_OPEN: self.door.open, Action.DOOR_CLOSE: self.door.close}  
  12.         self.lastAction = action  
  13.         # Get the function object from switcher dictionary  
  14.         function = switcher.get(action, None)  
  15.         # Execute the function  
  16.         function()  
  17.   
  18.     def unDoExecute(self):  
  19.         switcher = {Action.DOOR_OPEN: self.door.close, Action.DOOR_CLOSE: self.door.open}  
  20.         # Get the function object from switcher dictionary  
  21.         function = switcher.get(self.lastAction, None)  
  22.         # Execute the function  
  23.         function()  
Below is the Door class, it actually has core logic implementation:
  1. class Door :  
  2.     def open(self):  
  3.         print("------------Door Opened---------------")  
  4.   
  5.     def close(self) :  
  6.         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.   
  5. if __name__ == "__main__":  
  6.     command: Command = DoorCommand()  
  7.     command.execute(Action.DOOR_OPEN)  
  8.     command.execute(Action.DOOR_CLOSE)  
  9.     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.