Card 03/ 09
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.
class Strategy(ABC):
@abstractmethod
def execute(self, a: int, b: int) -> int: ...Concrete strategies
Implement the operation, one algorithm per class.
class ConcreteStrategyAdd(Strategy):
def execute(self, a: int, b: int) -> int:
return a + bContext
Holds a strategy, lets the client replace it, and calls it without checking which one it is.
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.
context = Context(ConcreteStrategyAdd())
context.set_strategy(ConcreteStrategyMultiply())The complete template
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))ConcreteStrategyAdd: 7
ConcreteStrategyMultiply: 12public 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);
}
}ConcreteStrategyAdd: 7
ConcreteStrategyMultiply: 12interface 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));ConcreteStrategyAdd: 7
ConcreteStrategyMultiply: 12The 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.
← → move through sections and cards