DEV Community

Marouane Goumri
Marouane Goumri

Posted on

Stop Using Long if-else Chains: Use the Command Pattern in Python

Have you ever found yourself with a long if-else or switch-case block in your code? This is quite common when dealing with user inputs, commands, or event-based logic. But over time, these chains can grow out of control and become a nightmare to maintain.

Enter the Command Pattern.

The Command Pattern is a behavioral design pattern that turns requests into objects, allowing you to parametrize methods with actions, delay execution, and create queues of operations. It's especially useful when your code has many conditional statements.

Let’s dive in and see how you can refactor your code to be cleaner, more maintainable, and easier to extend.

Image description

Traditional if-else Block

Imagine you have a program that handles different operations like opening, saving, or printing a document based on user input. You might be tempted to write something like this:

def handle_command(command):
    if command == "open":
        open_document()
    elif command == "save":
        save_document()
    elif command == "print":
        print_document()
    else:
        raise ValueError("Unknown command")

def open_document():
    print("Document opened")

def save_document():
    print("Document saved")

def print_document():
    print("Document printed")

Enter fullscreen mode Exit fullscreen mode

This works fine, but as more commands are added, the if-else block will grow and make your code less readable and harder to maintain.

Refactoring with the Command Pattern
With the Command Pattern, we encapsulate each operation (or command) in its own class, providing a cleaner and more flexible design.

Step 1: Define a Command Interface

We’ll start by defining a simple command interface (or base class in Python):

from abc import ABC, abstractmethod

class Command(ABC):
    @abstractmethod
    def execute(self):
        pass

Enter fullscreen mode Exit fullscreen mode

Each command will implement the execute() method, which contains the logic for the operation.

Step 2: Implement Concrete Commands

Now, we’ll create concrete command classes for each operation. Each command will implement the execute() method to carry out its specific task.

class OpenCommand(Command):
    def execute(self):
        print("Document opened")

class SaveCommand(Command):
    def execute(self):
        print("Document saved")

class PrintCommand(Command):
    def execute(self):
        print("Document printed")

Enter fullscreen mode Exit fullscreen mode

Step 3: Create a Command Invoker

Next, we need something to invoke these commands based on user input. Instead of a long if-else block, we can use a dictionary to map commands to their corresponding classes.

class CommandInvoker:
    def __init__(self):
        self.commands = {
            "open": OpenCommand(),
            "save": SaveCommand(),
            "print": PrintCommand(),
        }

    def handle_command(self, command):
        if command in self.commands:
            self.commands[command].execute()
        else:
            raise ValueError("Unknown command")

Enter fullscreen mode Exit fullscreen mode

Now, our CommandInvoker class acts as a centralized place for handling commands.

Step 4: Usage

Let’s see how this works in practice:

if __name__ == "__main__":
    invoker = CommandInvoker()

    invoker.handle_command("open")
    invoker.handle_command("save")
    invoker.handle_command("print")

Enter fullscreen mode Exit fullscreen mode

Why This is Better

  • Scalability: Adding new commands is as simple as adding a new class and updating the commands dictionary.

  • Separation of Concerns: Each command is responsible for its own behavior, making the code more modular and easier to understand.

  • Flexibility: Commands can be queued, delayed, or executed conditionally without modifying the core logic.

Conclusion

The Command Pattern is a powerful tool that can help you eliminate complex if-else chains and create a more organized, maintainable codebase. It’s particularly useful in scenarios where you have many operations or actions based on user input.

So next time you find yourself writing a giant conditional block, consider refactoring your code with the Command Pattern!

Happy coding!

Top comments (0)