Skip to content

Commit e2cfb81

Browse files
authored
Merge pull request #18 from ghimiresdp/feature/dp
Add command design pattern
2 parents 0fe8aa4 + 0666aa3 commit e2cfb81

3 files changed

Lines changed: 153 additions & 2 deletions

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ _[**Notes section**](#notes) first to get started with python._
3434
- [Design Patterns](src/design_patterns/README.md)
3535
- [Adapter Pattern](src/design_patterns/adapter.py)
3636
- [Builder Pattern](src/design_patterns/builder.py)
37-
- Command Pattern
37+
- [Command Pattern](src/design_patterns/command.py)
3838
- [Decorator Pattern](src/design_patterns/decorator.py)
3939
- [Factory Pattern](src/design_patterns/factory.py)
4040
- Observer Pattern

src/design_patterns/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ _make it as simpler as possible to understand the basic concept in each topic._
1212

1313
- [Adapter Pattern](adapter.py)
1414
- [Builder Pattern](builder.py)
15-
- Command Pattern
15+
- [Command Pattern](command.py)
1616
- [Decorator Pattern](decorator.py)
1717
- [Factory Pattern](factory.py)
1818
- Observer Pattern

src/design_patterns/command.py

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
"""
2+
Command Design Pattern
3+
-----------------------
4+
5+
Command Design pattern is a design pattern in which each request is
6+
encapsulated as an object called command. As the command easily capture the
7+
request along with the object and it's method to invoke, we can easily pass
8+
those requests.
9+
10+
Key Components of a command design pattern is as follows:
11+
12+
1. Command Interface: Defines the abstract method `execute` for all concrete commands
13+
2. Concrete Command : A command that implements Command Interface
14+
3. Receiver : An object that performs the operation
15+
4. Invoker : An object that stores and executes commands
16+
5. Client : An object that configures command objects
17+
18+
One of the popular usecase of the command design pattern is game development.
19+
We can encapsulate the behavior of different objects with the single command and
20+
each operations can be invoked using `execute()` method.
21+
"""
22+
23+
from abc import ABC, abstractmethod
24+
from enum import Enum
25+
26+
27+
class Command(ABC):
28+
"""
29+
This is a Command Interface that defines the blueprint for concrete command.
30+
"""
31+
32+
@abstractmethod
33+
def execute(self):
34+
pass
35+
36+
37+
class Player:
38+
def run(self):
39+
print("Player Running")
40+
41+
def jump(self):
42+
print("Player Jumping")
43+
44+
45+
class Tank:
46+
def move(self):
47+
print("Tank Moving")
48+
49+
def fire(self):
50+
print("Tank Firing")
51+
52+
53+
class PlayerRunCommand(Command):
54+
"""
55+
This is a concrete command that implements the Command Interface.
56+
"""
57+
58+
def __init__(self, player: Player) -> None:
59+
self.player = player
60+
61+
def execute(self):
62+
self.player.run()
63+
64+
65+
class PlayerJumpCommand(Command):
66+
def __init__(self, player: Player) -> None:
67+
self.player = player
68+
69+
def execute(self):
70+
self.player.jump()
71+
72+
73+
class TankMoveCommand(Command):
74+
def __init__(self, tank: Tank) -> None:
75+
self.tank = tank
76+
77+
def execute(self):
78+
self.tank.move()
79+
80+
81+
class TankFireCommand(Command):
82+
def __init__(self, tank: Tank) -> None:
83+
self.tank = tank
84+
85+
def execute(self):
86+
self.tank.fire()
87+
88+
89+
class Keys(Enum):
90+
UP = 1
91+
SPACE = 2
92+
93+
94+
class Controller:
95+
"""
96+
This is an invoker that stores and executes command on `key_press`
97+
"""
98+
99+
def __init__(self, commands: dict[Keys, Command]) -> None:
100+
self.commands = commands
101+
102+
def key_press(self, key: Keys):
103+
command = self.commands.get(key)
104+
"""
105+
The command object here is a receiver that run command
106+
"""
107+
if command:
108+
print(f"[ {key:^10s} ]: ", end="")
109+
command.execute()
110+
111+
112+
if __name__ == "__main__":
113+
player = Player()
114+
tank = Tank()
115+
"""
116+
Here, player_controller and tank_controller are clients that creates and
117+
configures command objects
118+
"""
119+
120+
player_controller = Controller(
121+
{
122+
Keys.UP: PlayerRunCommand(player),
123+
Keys.SPACE: PlayerJumpCommand(player),
124+
}
125+
)
126+
tank_controller = Controller(
127+
{
128+
Keys.UP: TankMoveCommand(tank),
129+
Keys.SPACE: TankFireCommand(tank),
130+
}
131+
)
132+
133+
print("[ Player Active ]".center(40, "="))
134+
player_controller.key_press(Keys.UP) # command is invoked
135+
player_controller.key_press(Keys.SPACE)
136+
137+
print("[ Tank Active ]".center(40, "="))
138+
tank_controller.key_press(Keys.UP)
139+
tank_controller.key_press(Keys.SPACE)
140+
141+
"""
142+
OUTPUT:
143+
144+
===========[ Player Active ]============
145+
[ Keys.UP ]: Player Running
146+
[ Keys.SPACE ]: Player Jumping
147+
============[ Tank Active ]=============
148+
[ Keys.UP ]: Tank Moving
149+
[ Keys.SPACE ]: Tank Firing
150+
151+
"""

0 commit comments

Comments
 (0)