From grimoire
Encapsulates interchangeable algorithms in separate classes, enabling runtime swapping without conditional logic. Useful when multiple behaviors exist for a task.
How this skill is triggered — by the user, by Claude, or both
Slash command
/grimoire:apply-strategy-patternThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Define a family of algorithms, encapsulate each one, and make them interchangeable — letting the algorithm vary independently from the clients that use it.
Define a family of algorithms, encapsulate each one, and make them interchangeable — letting the algorithm vary independently from the clients that use it.
Adopted by: Java's Comparator interface (Strategy for sorting — used in every
Collections.sort() call), Python's sorted(key=...) (a Strategy as a first-class
function), scikit-learn's estimator API (every ML algorithm is a Strategy implementing
fit()/predict() — the library's entire design), and AWS SDK's configurable
retry strategies (RetryPolicy interface).
Impact: GoF documents that Strategy eliminates conditional logic that selects
algorithms at runtime. scikit-learn's adoption of Strategy is directly responsible for
its plug-and-play model comparison: swapping RandomForestClassifier for SVC requires
one line — because both implement the same Strategy interface.
Why best: if/elif dispatch — the alternative — couples the client to every
algorithm variant and requires modification for every new algorithm. Strategy makes each
algorithm independently changeable, testable, and composable without touching the client.
Sources: Gamma et al. (1994) pp. 315–323; Java Comparator specification;
scikit-learn API documentation
from abc import ABC, abstractmethod
class SortStrategy(ABC):
@abstractmethod
def sort(self, data: list) -> list: ...
class BubbleSortStrategy(SortStrategy):
def sort(self, data: list) -> list:
data = list(data)
n = len(data)
for i in range(n):
for j in range(0, n - i - 1):
if data[j] > data[j + 1]:
data[j], data[j + 1] = data[j + 1], data[j]
return data
class QuickSortStrategy(SortStrategy):
def sort(self, data: list) -> list:
if len(data) <= 1:
return data
pivot = data[len(data) // 2]
left = [x for x in data if x < pivot]
mid = [x for x in data if x == pivot]
right = [x for x in data if x > pivot]
return self.sort(left) + mid + self.sort(right)
class Sorter:
def __init__(self, strategy: SortStrategy):
self._strategy = strategy
def set_strategy(self, strategy: SortStrategy) -> None:
self._strategy = strategy
def sort(self, data: list) -> list:
return self._strategy.sort(data)
sorter = Sorter(BubbleSortStrategy())
print(sorter.sort([3, 1, 4, 1, 5])) # [1, 1, 3, 4, 5]
sorter.set_strategy(QuickSortStrategy())
print(sorter.sort([3, 1, 4, 1, 5])) # [1, 1, 3, 4, 5] — same result, different algorithm
from typing import Callable
class Sorter:
def __init__(self, strategy: Callable[[list], list] = sorted):
self._strategy = strategy
def sort(self, data: list) -> list:
return self._strategy(data)
# Use built-ins or lambdas as strategies — no class needed
sorter = Sorter(strategy=lambda d: sorted(d, reverse=True))
Use class-based strategies when state is needed; function strategies for stateless algorithms.
reverse=True flag is cleaner than two strategy classes.Passing strategy selection logic into the strategy. A Strategy that asks "which variant should I use?" is no longer a Strategy — it's a dispatcher. Each Strategy implements exactly one algorithm.
State leakage between calls. Strategies that store results from previous sort() calls produce bugs when reused. Strategies should be stateless or clearly document what state they maintain.
Using Strategy when Template Method is the right pattern. If all algorithms share the same skeleton but differ only in specific steps, apply-template-method-pattern is more appropriate than several full Strategy implementations.
npx claudepluginhub jeffreytse/grimoire --plugin grimoireEncapsulates interchangeable algorithms behind a common interface for runtime selection, eliminating large if/else chains. Provides code examples for both class-based and idiomatic TypeScript function-based strategies.
Defines an algorithm skeleton in a base class with abstract steps for subclasses to override. Use when multiple classes share the same structure but differ in specific steps.
Generates PHP 8.4 Strategy pattern with interface, concrete strategies, resolver, optional service, and unit tests for interchangeable algorithm families like pricing or sorting.