Featured image of post BP3 - Command - Learn Design Pattern From Simple Things

BP3 - Command - Learn Design Pattern From Simple Things

As an army commander, you have to plan all the tasks for the soldiers, so that they can execute them. This process is called command.

Command is a behavioral design pattern: 🖤🖤🖤🖤🤍

What is Command?

Command is a technique that object commander is used to encapsulate needed information resource, soldier to execute the task at a later time.

Command diagram

Why use Command?

  • Its layout is easy to understand and has good extensibility when more logic comes later.

Question: I hate the Command, what are the alternatives?

Answer: Just code as normal and ignore this pattern, everything in Python is an object, so you can store any object and execute a callback easily.

NoCommander

When to use Command?

Question: When do I use Command?

Answer: When you have a lot of tasks, it is necessary to store and plan for them. Then (maybe after a delay) execute them as planned.

Input:

  • Having resources(Resource for the First Task, Resource for the Main Task, Resource for the Last Task),
  • Having tasks in order first_task(NonSoldierCommand.execute), main_task , last_task(SoldierCommand.execute):
1
# nothing here

Expected Output:

  • Resources are appropriately allocated to task, tasks are properly planned first, then it will be executed once the command is activated.
1
2
3
4
5
6
7
Commander: the first task is:
    💣NonSoldierCommand.executing: (Resource for the First Task)
Commander: the main task is:
    🧨Commander.executing: (Resource for the Main Task)
Commander: the last task is:
    💣SoldierCommand.executing: (<class '__main__.Soldier'>, Resource for the Last Task)
        Soldier.do_something with: (Resource for the Last Task)

How to implement Command?

Non-Command implementation:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
def non_soldier_command_execute(payload):
    print(f"    💣NonSoldierCommand.executing: ({payload})")


def soldier_command_execute(soldier, resource):
    print(f"    💣SoldierCommand.executing: ({type(soldier)}, {resource})")
    soldier.do_something(resource)


class Soldier:
    def do_something(self, resource):
        print(f"        Soldier.do_something with: ({resource})")


if __name__ == "__main__":
    # no planning here, just do everything at once
    print("Commander: the first task is:")
    non_soldier_command_execute("Resource for the First Task")

    print("Commander: the main task is:")
    print(f"    🧨Commander.executing: (Resource for the Main Task)")

    print("Commander: the last task is:")
    soldier = Soldier()
    soldier_command_execute(soldier, "Resource for the Last Task")

Command Implementation:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
from abc import ABC, abstractmethod


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


class NonSoldierCommand(Command):
    def __init__(self, payload):
        self._payload = payload

    def execute(self):
        print(f"    💣NonSoldierCommand.executing: ({self._payload})")


class SoldierCommand(Command):
    def __init__(self, soldier, resource):
        self._soldier = soldier
        self._resource = resource

    def execute(self):
        print(f"    💣SoldierCommand.executing: ({type(self._soldier)}, {self._resource})")
        self._soldier.do_something(self._resource)


class Soldier:
    def do_something(self, resource):
        print(f"        Soldier.do_something with: ({resource})")


class Commander:
    _first_task = None
    _last_task = None

    def init_first_command(self, command):
        self._first_task = command

    def init_last_command(self, command):
        self._last_task = command

    def execute_main_command(self):
        print("Commander: the first task is:")
        if isinstance(self._first_task, Command):
            self._first_task.execute()

        print("Commander: the main task is:")
        print(f"    🧨Commander.executing: (Resource for the Main Task)")

        print("Commander: the last task is:")
        if isinstance(self._last_task, Command):
            self._last_task.execute()


if __name__ == "__main__":
    commander = Commander()

    # commander init: a command encapsulating needed information(resource) to execute the task at a later time.
    non_soldier_command = NonSoldierCommand("Resource for the First Task")
    commander.init_first_command(non_soldier_command)

    # commander init: a command encapsulating needed information(soldier, resource) to execute the task at a later time.
    soldier = Soldier()
    soldier_command = SoldierCommand(soldier, "Resource for the Last Task")
    commander.init_last_command(soldier_command)

    # after planning, this is the later time, time to execute the tasks initiated by the commander
    commander.execute_main_command()

Source Code

Made with the laziness 🦥
by a busy guy