Card 03/ 09

CodeDifficulty: Intermediate3 min

Strategy Template in Python, Java and TypeScript

Two strategies, one context, and the same call giving two results.

The Strategy template is the pattern in its pure form, with the participant names from the class diagram. One context adds 3 and 4 with one strategy, then multiplies them after the client swaps in another, so the same call gives two results. The steps add each participant in Python, and the tabs give the complete program in three languages, each with its output.

Building the template one participant at a time

Strategy

Declares the one operation every algorithm provides.

py
class Strategy(ABC):
    @abstractmethod
    def execute(self, a: int, b: int) -> int: ...

Concrete strategies

Implement the operation, one algorithm per class.

py
class ConcreteStrategyAdd(Strategy):
    def execute(self, a: int, b: int) -> int:
        return a + b

Context

Holds a strategy, lets the client replace it, and calls it without checking which one it is.

py
class Context:
    def set_strategy(self, strategy: Strategy) -> None:
        self._strategy = strategy

    def do_work(self, a: int, b: int) -> str:
        return f"{type(self._strategy).__name__}: {self._strategy.execute(a, b)}"

Client

Chooses the strategy and hands it over.

py
context = Context(ConcreteStrategyAdd())
context.set_strategy(ConcreteStrategyMultiply())

The complete template

py
from abc import ABC, abstractmethod


class Strategy(ABC):
    @abstractmethod
    def execute(self, a: int, b: int) -> int: ...


class ConcreteStrategyAdd(Strategy):
    def execute(self, a: int, b: int) -> int:
        return a + b


class ConcreteStrategyMultiply(Strategy):
    def execute(self, a: int, b: int) -> int:
        return a * b


class Context:
    def __init__(self, strategy: Strategy) -> None:
        self._strategy = strategy

    def set_strategy(self, strategy: Strategy) -> None:
        self._strategy = strategy

    def do_work(self, a: int, b: int) -> str:
        return f"{type(self._strategy).__name__}: {self._strategy.execute(a, b)}"


context = Context(ConcreteStrategyAdd())
print(context.do_work(3, 4))
context.set_strategy(ConcreteStrategyMultiply())
print(context.do_work(3, 4))
OutputRan with python:3.12-slim (Python 3.12.13)
ConcreteStrategyAdd: 7
ConcreteStrategyMultiply: 12
`do_work` calls `execute` on whichever strategy the context holds.
java
public class StTemplate {
    public static void main(String[] args) {
        Context context = new Context(new ConcreteStrategyAdd());
        System.out.println(context.doWork(3, 4));
        context.setStrategy(new ConcreteStrategyMultiply());
        System.out.println(context.doWork(3, 4));
    }
}

interface Strategy {
    int execute(int a, int b);
}

class ConcreteStrategyAdd implements Strategy {
    public int execute(int a, int b) {
        return a + b;
    }
}

class ConcreteStrategyMultiply implements Strategy {
    public int execute(int a, int b) {
        return a * b;
    }
}

class Context {
    private Strategy strategy;

    Context(Strategy strategy) {
        this.strategy = strategy;
    }

    void setStrategy(Strategy strategy) {
        this.strategy = strategy;
    }

    String doWork(int a, int b) {
        return strategy.getClass().getSimpleName() + ": " + strategy.execute(a, b);
    }
}
OutputRan with eclipse-temurin:21-jdk (Java 21.0.12)
ConcreteStrategyAdd: 7
ConcreteStrategyMultiply: 12
`Context` depends only on the `Strategy` interface.
ts
interface Strategy {
  execute(a: number, b: number): number;
}

class ConcreteStrategyAdd implements Strategy {
  execute(a: number, b: number): number {
    return a + b;
  }
}

class ConcreteStrategyMultiply implements Strategy {
  execute(a: number, b: number): number {
    return a * b;
  }
}

class Context {
  constructor(private strategy: Strategy) {}

  setStrategy(strategy: Strategy): void {
    this.strategy = strategy;
  }

  doWork(a: number, b: number): string {
    return `${this.strategy.constructor.name}: ${this.strategy.execute(a, b)}`;
  }
}

const context = new Context(new ConcreteStrategyAdd());
console.log(context.doWork(3, 4));
context.setStrategy(new ConcreteStrategyMultiply());
console.log(context.doWork(3, 4));
OutputRan with node:22-slim (Node 22.23.1), TypeScript 5.9.3
ConcreteStrategyAdd: 7
ConcreteStrategyMultiply: 12
The constructor's `private strategy` both declares and assigns the field.

The two lines of output come from the same call, do_work(3, 4), on the same context. Only the object behind _strategy changed between them, and the context has no if that mentions either class. A third strategy, say subtraction, would be one new class and no edit to Context.