Strategy Pattern

Updated Nov 25, 2025

Strategy Pattern

Intent:

The Strategy Pattern lets you choose different ways to do the same task. Instead of writing one big function with lots of if-else statements, you create separate classes for each way (strategy). You can then pick which strategy to use whenever you need it.

When to Use:

Use the Strategy Pattern when:

  • You have multiple ways to do the same thing
  • You want to switch between different methods easily
  • You want to avoid long if-else chains in your code
  • You might add new ways in the future

Key Characteristics:

  • Each way of doing something is a separate class (strategy)
  • All strategies do the same job but in different ways
  • You can switch between strategies easily
  • Easy to add new strategies without changing old code

Think of it like different ways to win in tic-tac-toe - you can win horizontally, vertically, or diagonally. Each is a different strategy, but they all check if you won. Instead of writing one big function with if-else statements, you create separate classes for each way to check.


⭕ Example: Tic-Tac-Toe Winning Strategies

Let's say we're building a tic-tac-toe game. We need to check if a player has won. There are three ways to win: horizontal, vertical, or diagonal.

Without Strategy Pattern: We would write one big function with if-else statements checking all three ways.

With Strategy Pattern: We create separate classes for each way to check (horizontal, vertical, diagonal). Then we can pick which one to use, or even check all of them one by one. This makes the code cleaner and easier to understand.

Step 1: Define Strategy Interface

# winning_strategy.py from abc import ABC, abstractmethod class WinningStrategy(ABC): @abstractmethod def check_win(self, board, player): pass # Each strategy will check win differently

Step 2: Create Horizontal Win Strategy

# horizontal_strategy.py from winning_strategy import WinningStrategy class HorizontalStrategy(WinningStrategy): def check_win(self, board, player): """Check if player won horizontally (any row)""" print(f"[Horizontal Strategy] Checking horizontal win for {player}...") for row in board: if all(cell == player for cell in row): print(f"[Horizontal Strategy] {player} won horizontally!") return True print(f"[Horizontal Strategy] No horizontal win for {player}") return False

Step 3: Create Vertical Win Strategy

# vertical_strategy.py from winning_strategy import WinningStrategy class VerticalStrategy(WinningStrategy): def check_win(self, board, player): """Check if player won vertically (any column)""" print(f"[Vertical Strategy] Checking vertical win for {player}...") for col in range(3): if all(board[row][col] == player for row in range(3)): print(f"[Vertical Strategy] {player} won vertically!") return True print(f"[Vertical Strategy] No vertical win for {player}") return False

Step 4: Create Diagonal Win Strategy

# diagonal_strategy.py from winning_strategy import WinningStrategy class DiagonalStrategy(WinningStrategy): def check_win(self, board, player): """Check if player won diagonally""" print(f"[Diagonal Strategy] Checking diagonal win for {player}...") # Check main diagonal (top-left to bottom-right) if all(board[i][i] == player for i in range(3)): print(f"[Diagonal Strategy] {player} won on main diagonal!") return True # Check anti-diagonal (top-right to bottom-left) if all(board[i][2-i] == player for i in range(3)): print(f"[Diagonal Strategy] {player} won on anti-diagonal!") return True print(f"[Diagonal Strategy] No diagonal win for {player}") return False

Step 5: Create Game Context

# tic_tac_toe_game.py from winning_strategy import WinningStrategy class TicTacToeGame: def __init__(self): self.board = [[' ' for _ in range(3)] for _ in range(3)] self.winning_strategy = None # Will be set to a strategy def set_winning_strategy(self, strategy: WinningStrategy): """Set which strategy to use for checking wins""" self.winning_strategy = strategy print(f"\n[Game] Strategy set to: {strategy.__class__.__name__}") def make_move(self, row, col, player): """Make a move on the board""" if self.board[row][col] == ' ': self.board[row][col] = player print(f"[Game] {player} placed at ({row}, {col})") return True return False def check_win(self, player): """Check if player won using current strategy""" if self.winning_strategy: return self.winning_strategy.check_win(self.board, player) return False def display_board(self): """Display the current board""" print("\n[Game] Current Board:") for i, row in enumerate(self.board): print(f" {' | '.join(row)}") if i < 2: print(" " + "-" * 9)

Step 6: Use the Strategy Pattern (Client Code)

# main.py from tic_tac_toe_game import TicTacToeGame from horizontal_strategy import HorizontalStrategy from vertical_strategy import VerticalStrategy from diagonal_strategy import DiagonalStrategy # Create game game = TicTacToeGame() # Test 1: Horizontal Win print("=== Test 1: Horizontal Win ===") game.set_winning_strategy(HorizontalStrategy()) game.make_move(0, 0, 'X') game.make_move(0, 1, 'X') game.make_move(0, 2, 'X') game.display_board() game.check_win('X') # Reset game game = TicTacToeGame() # Test 2: Vertical Win print("\n=== Test 2: Vertical Win ===") game.set_winning_strategy(VerticalStrategy()) game.make_move(0, 1, 'O') game.make_move(1, 1, 'O') game.make_move(2, 1, 'O') game.display_board() game.check_win('O') # Reset game game = TicTacToeGame() # Test 3: Diagonal Win print("\n=== Test 3: Diagonal Win ===") game.set_winning_strategy(DiagonalStrategy()) game.make_move(0, 0, 'X') game.make_move(1, 1, 'X') game.make_move(2, 2, 'X') game.display_board() game.check_win('X') # Test 4: Check all strategies print("\n=== Test 4: Check All Strategies ===") game = TicTacToeGame() game.make_move(0, 0, 'X') game.make_move(1, 1, 'X') game.make_move(2, 2, 'X') game.display_board() strategies = [HorizontalStrategy(), VerticalStrategy(), DiagonalStrategy()] for strategy in strategies: game.set_winning_strategy(strategy) if game.check_win('X'): print(f"[Game] Winner found using {strategy.__class__.__name__}!") break

Output:

=== Test 1: Horizontal Win ===

[Game] Strategy set to: HorizontalStrategy
[Game] X placed at (0, 0)
[Game] X placed at (0, 1)
[Game] X placed at (0, 2)

[Game] Current Board:
  X | X | X
  ---------
     |   |   
  ---------
     |   |   
[Horizontal Strategy] Checking horizontal win for X...
[Horizontal Strategy] X won horizontally!

=== Test 2: Vertical Win ===

[Game] Strategy set to: VerticalStrategy
[Game] O placed at (0, 1)
[Game] O placed at (1, 1)
[Game] O placed at (2, 1)

[Game] Current Board:
     | O |   
  ---------
     | O |   
  ---------
     | O |   
[Vertical Strategy] Checking vertical win for O...
[Vertical Strategy] O won vertically!

=== Test 3: Diagonal Win ===

[Game] Strategy set to: DiagonalStrategy
[Game] X placed at (0, 0)
[Game] X placed at (1, 1)
[Game] X placed at (2, 2)

[Game] Current Board:
  X |   |   
  ---------
     | X |   
  ---------
     |   | X
[Diagonal Strategy] Checking diagonal win for X...
[Diagonal Strategy] X won on main diagonal!

=== Test 4: Check All Strategies ===
[Game] X placed at (0, 0)
[Game] X placed at (1, 1)
[Game] X placed at (2, 2)

[Game] Current Board:
  X |   |   
  ---------
     | X |   
  ---------
     |   | X

[Game] Strategy set to: HorizontalStrategy
[Horizontal Strategy] Checking horizontal win for X...
[Horizontal Strategy] No horizontal win for X

[Game] Strategy set to: VerticalStrategy
[Vertical Strategy] Checking vertical win for X...
[Vertical Strategy] No vertical win for X

[Game] Strategy set to: DiagonalStrategy
[Diagonal Strategy] Checking diagonal win for X...
[Diagonal Strategy] X won on main diagonal!
[Game] Winner found using DiagonalStrategy!

✅ Benefits

1. Easy to Switch:

  • You can change which strategy to use anytime
  • Add new strategies without breaking old code

2. Cleaner Code:

  • No need for long if-else chains
  • Each strategy is in its own class, easy to read

3. One Job Per Class:

  • Each strategy does one thing well
  • Easy to understand what each strategy does

4. Easy to Add More:

  • Want a new way to do something? Just add a new strategy class
  • Don't need to change any existing code

🎯 Key Points

  • Strategy Pattern puts each way of doing something in its own class
  • All strategies can be used the same way (interchangeable)
  • You choose which strategy to use when you need it
  • Easy to add new strategies later
  • No need for messy if-else statements

🌟 Quick Summary

  • Problem: You have multiple ways to do the same thing, but using if-else statements makes your code messy and hard to read
  • Solution: Create a separate class for each way (strategy), so each one is clean and organized
  • Benefit: Your code is cleaner, easier to understand, and you can easily add new ways or switch between them
  • Example: Checking if someone won tic-tac-toe - you can check horizontally, vertically, or diagonally, each in its own strategy class

🎉 End

The Strategy Pattern helps you organize different algorithms cleanly. It's perfect when you have multiple ways to accomplish the same task!