---
title: "BP2 - Strategy - Learn Design Pattern From Simple Things"
description: "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."
pubDate: "2022-12-10"
lang: "en"
slug: "bp2-strategy-learn-design-pattern-from-simple-things"
url: "https://hoangyell.com/bp2-strategy-learn-design-pattern-from-simple-things/"
author: "HoangYell"
categories: ["Software Craft"]
tags: ["design-patterns", "behavioral-patterns"]
heroImage: "https://raw.githubusercontent.com/HoangGeek/store/main/webp/hc2bVac.webp"
---

_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.

![Image](https://raw.githubusercontent.com/HoangGeek/store/main/webp/206896998-acbc4566-86ba-4829-913e-facb1c2ce8de.webp)

## 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!_

![Image](https://img-9gag-fun.9cache.com/photo/aogvMpm_700bwp.webp)

## 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 `attack` with multiple logic/plugins `TikiTaka, CounterAttack` being swapped out for each situation 🔄.

``` python
"""
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 `FootballClub` has the ability to dynamically run different `pass_the_ball` logic/plugins at different times:
    - at the start: `pass_the_ball` in CounterAttack style.
    - at the end: `pass_the_ball` in TikiTaka style.

``` shell
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:
``` python
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:
``` python
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()
```

[Source Code](https://github.com/HoangYell/Design-Pattern-From-Simple-Things/blob/main/bp2_strategy.py)
