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 wants the employees to focus on work and not get distracted by social media. So he decides to block some websites on the corporate network during working hours.
-
SP6 - Object Pool - Learn Design Pattern From Simple Things
Producing planes on a large scale is expensive, but fortunately the manufactured raw parts are always stored in the pool, thereby reducing duplication in the production process.
-
SP5 - Facade - Learn Design Pattern From Simple Things
There are many departments in the building and you feel confused! By opening the entrances from the facade according to purposes, you simply follow the pre-arranged flow.