BP2 - Strategy - Learn Design Pattern From Simple Things
As the coach of a strong team, you plan to attack to find a goal and then prioritize possession to preserve the score. This combination is called strategy.
Strategy is a behavioral design pattern: 🖤🖤🖤🖤🖤
What is Strategy?
Strategy is a technique to be able to insert a new logic/plugin TikiTaka, CounterAttack into a main object FootballClub dynamically.
Why use Strategy?
- Defining new logic/plugin will not change the code of the main object.
- The new logic/plugin will only be plugged in as needed, make the code more comprehensible.
Question: I hate the Strategy, what are the alternatives?
Answer: You can create multiple logic/plugins counter_attack_pass_the_ball, tiki_taka_pass_the_ball directly in main object instead of Plugins, but it’s not pretty!
When to use Strategy?
Question: When do I use Strategy?
Answer: When you have multiple logic/plugins TikiTaka, CounterAttack for an object and logic/plugins usage changes over time.
Input:
- Having a main object
FootballClub:- There is a main feature
attackwith multiple logic/pluginsTikiTaka, CounterAttackbeing swapped out for each situation 🔄.
- There is a main feature
"""
class FootballClub:
def attack(self):
formation = [
["LB", "CB", "CB", "CB"],
["LCM", "CDM", "RCM"],
["LW", "CF", "RW"],
]
...pass_the_ball...
"""
import random
from abc import ABC, abstractmethod
class Strategy(ABC):
name = ""
@abstractmethod
def pass_the_ball(self, formation):
pass
class TikiTaka(Strategy):
name = "TikiTaka"
def pass_the_ball(self, formation):
defenders = formation[0]
midfielder_forwards = [*formation[1], *formation[2]]
random.shuffle(defenders)
random.shuffle(midfielder_forwards)
return [*defenders, *midfielder_forwards]
class CounterAttack(Strategy):
name = "CounterAttack"
def pass_the_ball(self, formation):
defenders = random.choice(formation[0])
midfielders = random.choice(formation[1])
forwards = random.choice(formation[2])
return [defenders, midfielders, forwards]
Expected Output:
- The main object
FootballClubhas the ability to dynamically run differentpass_the_balllogic/plugins at different times:- at the start:
pass_the_ballin CounterAttack style. - at the end:
pass_the_ballin TikiTaka style.
- at the start:
Manager: Hey team! apply CounterAttack
LB >> CDM >> RW >> GOAAAALLL!!!
Manager: Hey team! apply TikiTaka
CB >> CB >> LB >> CB >> CDM >> RCM >> RW >> LW >> LCM >> CF >> GOAAAALLL!!!
How to implement Strategy?
Non-Strategy implementation:
class FootballClub:
def __init__(self, strategy):
self._strategy = strategy
@property
def strategy(self):
return self._strategy
@strategy.setter
def strategy(self, strategy):
self._strategy = strategy
def attack(self):
formation = [
["LB", "CB", "CB", "CB"],
["LCM", "CDM", "RCM"],
["LW", "CF", "RW"],
]
result = []
if self._strategy == "TikiTaka":
result = self.tiki_taka_pass_the_ball(formation)
elif self._strategy == "CounterAttack":
result = self.counter_attack_pass_the_ball(formation)
result.append("GOAAAALLL!!!")
print(" >> ".join(result))
def tiki_taka_pass_the_ball(self, formation):
defenders = formation[0]
midfielder_forwards = [*formation[1], *formation[2]]
random.shuffle(defenders)
random.shuffle(midfielder_forwards)
return [*defenders, *midfielder_forwards]
def counter_attack_pass_the_ball(self, formation):
defenders = random.choice(formation[0])
midfielders = random.choice(formation[1])
forwards = random.choice(formation[2])
return [defenders, midfielders, forwards]
if __name__ == "__main__":
strategy = "CounterAttack"
football_club = FootballClub(strategy)
print(f"Manager: Hey team! apply {strategy}")
football_club.attack()
strategy = "TikiTaka"
print(f"Manager: Hey team! apply {strategy}")
football_club.strategy = strategy
football_club.attack()
Strategy Implementation:
class FootballClub:
def __init__(self, strategy):
self._strategy = strategy
@property
def strategy(self):
return self._strategy
@strategy.setter
def strategy(self, strategy):
self._strategy = strategy
def attack(self):
formation = [
["LB", "CB", "CB", "CB"],
["LCM", "CDM", "RCM"],
["LW", "CF", "RW"],
]
result = self._strategy.pass_the_ball(formation)
result.append("GOAAAALLL!!!")
print(" >> ".join(result))
if __name__ == "__main__":
strategy = CounterAttack()
football_club = FootballClub(strategy)
print(f"Manager: Hey team! apply {strategy.name}")
football_club.attack()
strategy = TikiTaka()
print(f"Manager: Hey team! apply {strategy.name}")
football_club.strategy = strategy
football_club.attack()
Related posts
-
Verify vs Cert: The Python Requests Handbook
Understanding SSL/TLS in Python Requests: The 'verify' and 'cert' arguments explained with interactive animations.
-
SP7 - Proxy - Learn Design Pattern From Simple Things
The boss blocks social media so employees stay focused. That's exactly how the Proxy pattern works — controlling access between objects.
-
SP6 - Object Pool - Learn Design Pattern From Simple Things
Manufacturing planes is expensive, but raw parts are reused from a pool. That's the Object Pool pattern — reduce creation cost with smart reuse.
-
SP5 - Facade - Learn Design Pattern From Simple Things
Many departments, one entrance. The Facade pattern simplifies complex systems by exposing only what you need. Learn it from simple everyday things.