Skill: quochungto/bookforge-strategy-pattern-implementor (version 1.0.0)

--- name: strategy-pattern-implementor description: | Implement the Strategy pattern to encapsulate a family of interchangeable algorithms behind a common interface. Use when you have multiple conditional branches selecting between algorithm variants, when algorithms need different space-time trade-offs, when a class has multiple behaviors expressed as conditionals, or when you need to swap algorithms at runtime. Detects the key code smell — switch/if-else chains selecting behavior — and refactors to Strategy objects. version: 1.0.0 homepage: https://github.com/bookforge-ai/bookforge-skills/tree/main/books/design-patterns-gof/skills/strategy-pattern-implementor metadata: {"openclaw":{"emoji":"📚","homepage":"https://github.com/bookforge-ai/bookforge-skills"}} status: draft depends-on: - behavioral-pattern-selector source-books: - id: design-patterns-gof title: "Design Patterns: Elements of Reusable Object-Oriented Software" authors: ["Erich Gamma", "Richard Helm", "Ralph Johnson", "John Vlissides"] chapters: [5] pages: [48-50, 292-300] tags: [design-patterns, behavioral, gof, strategy, refactoring, algorithms, composition] execution: tier: 2 mode: full inputs: - type: code description: "Existing code with conditional branches selecting between algorithm variants, or a description of the algorithmic variation that needs encapsulation" tools-required: [TodoWrite, Read] tools-optional: [Grep, Edit] mcps-required: [] environment: "Any codebase. Language-agnostic — examples use Python but the pattern applies universally." --- # Strategy Pattern Implementor ## When to Use You have a class that selects between algorithm variants and need to refactor it so algorithms can vary independently from the clients that use them. This skill applies when: - A class contains `switch` statements or `if/else` chains that select between behavioral variants — **the primary code smell** - Multiple related classes differ only in their behavior (same structure, different computation) - You need different space-time trade-offs for the same operation (fast-and-approximate vs. slow-and-precise) - An algorithm uses data clients should not know about (complex internal data structures that would leak through the interface) - You need to swap the algorithm at runtime without changing the client Before starting, confirm: - Is this a **client-selected** algorithm switch (Strategy) rather than an **object self-transitioning** based on internal state (State)? If unsure, use `behavioral-pattern-selector` first. - Does the variation belong in the class itself, or is it better expressed via a superclass skeleton with subclass steps (Template Method via inheritance)? Strategy uses composition — the algorithm is a separate object, not a subclass. --- ## Process ### Step 1: Set Up Tracking and Identify the Conditional **ACTION:** Use `TodoWrite` to track progress, then locate the conditional code that signals the need for Strategy. **WHY:** The conditional block is the concrete artifact you are eliminating. Identifying it precisely — its location, what it selects between, and what data it touches — drives every subsequent decision about interface design and data passing. Without pinning this down first, the refactoring risks producing a Strategy structure that does not fit the actual variation. ``` TodoWrite: - [ ] Step 1: Locate the conditional and characterize the variation - [ ] Step 2: Define the Strategy interface - [ ] Step 3: Implement ConcreteStrategy classes - [ ] Step 4: Refactor the Context class - [ ] Step 5: Validate and apply optional optimizations ``` Locate the conditional using `Read` or `Grep`, then document: | Element | What to capture | |---------|----------------| | **Location** | File, class, method where the conditional lives | | **Variants** | How many branches? What does each compute? | | **Data required** | What data does each branch use from the context? | | **Selection point** | Who chooses the variant — the caller, a config value, or a runtime condition? | | **Change frequency** | How often are new variants added? Does this class change every time? | If working from a description rather than existing code, draft a minimal "before" sketch showing the conditional structure. --- ### Step 2: Define the Strategy Interface **ACTION:** Design the abstract Strategy interface — the single method (or small set of methods) that all ConcreteStrategies must implement. **WHY:** The Strategy interface is the contract that decouples the Context from all algorithm implementations. If it is too narrow (missing data the strategy needs), ConcreteStrategies will have to reach into the Context through back-channels, increasing coupling. If it is too wide (exposing data no strategy uses), the communication overhead between Strategy and Context grows. The interface must be general enough that you will not have to change it when adding new ConcreteStrategies — this is the central design decision of the pattern. **Two data-passing approaches — choose one:** | Approach | How it works | When to prefer | |----------|-------------|----------------| | **Take data to the strategy** | Context passes all needed data as parameters to the strategy method | Algorithm needs a bounded, well-known set of inputs; keeps Strategy and Context decoupled | | **Pass context as argument** | Strategy receives the Context object itself and requests what it needs | Algorithm needs variable or large amounts of context data; reduces parameter proliferation but couples Strategy to Context's interface | Design the interface method signature: ```python # Approach 1: explicit parameters (preferred when data set is bounded) class SortStrategy: def sort(self, data: list) -> list: raise NotImplementedError # Approach 2: context reference class SortStrategy: def sort(self, context: "Sorter") -> None: raise NotImplementedError ``` **Check:** Will a new ConcreteStrategy ever need data this interface does not provide? If yes, revise — you should not need to change the interface when adding strategies. --- ### Step 3: Implement ConcreteStrategy Classes **ACTION:** Extract each conditional branch into its own ConcreteStrategy class that implements the Strategy interface. **WHY:** Each branch in the original conditional is an independently varying algorithm. Making each one a class gives it a name (making the code self-documenting), an isolated scope for its data structures (preventing algorithm-specific complexity from polluting the Context), and a testable boundary (each strategy can be tested in isolation without instantiating the full Context). For each branch in the original conditional: 1. Create a class named after the algorithm it encapsulates (not after what it replaces — use domain terminology, e.g., `BubbleSortStrategy`, not `OldSortBranch`) 2. Implement the interface method with the branch's logic 3. Move any algorithm-specific private data into the ConcreteStrategy (not the Context) ```python class BubbleSortStrategy(SortStrategy): """Simple sort — O(n²), stable, no extra memory.""" def sort(self, data: list) -> list: result = data[:] n = len(result) for i in range(n): for j in range(0, n - i - 1): if result[j] > result[j + 1]: result[j], result[j + 1] = result[j + 1], result[j] return result class QuickSortStrategy(SortStrategy): """Fast sort — O(n log n) average, not stable, in-place.""" def sort(self, data: list) -> list: result = data[:] self._quicksort(result, 0, len(result) - 1) return result def _quicksort(self, arr, low, high): if low < high: pi = self._partition(arr, low, high) self._quicksort(arr, low, pi - 1) self._quicksort(arr, pi + 1, high) def _partition(self, arr, low, high): pivot = arr[high] i = low - 1 for j in range(low, high): if arr[j] <= pivot: i += 1 arr[i], arr[j] = arr[j], arr[i] arr[i + 1], arr[high] = arr[high], arr[i + 1] return i + 1 ``` **Stateless strategies as Flyweights:** If a ConcreteStrategy holds no instance state (all data comes from parameters), it can be shared across multiple Context instances. A single shared instance replaces per-context allocation. This optimization applies when strategies are lightweight and stateless — do not force it if the strategy needs per-invocation state. --- ### Step 4: Refactor the Context Class **ACTION:** Replace the conditional in the Context with a reference to a Strategy object and a delegation call. **WHY:** This is the core structural change. The Context no longer *knows* how to perform the algorithm — it only knows *that* an algorithm exists and how to invoke it. The conditional disappears entirely, replaced by a single delegation call. The Context becomes open to extension (new strategies) without modification, satisfying the open-closed principle. **Refactoring steps:** 1. Add a `strategy` attribute (initialized via constructor or setter) 2. Replace the entire conditional block with a single call to `self.strategy.algorithm_method(...)` 3. Remove any algorithm-specific data that has moved into ConcreteStrategy classes 4. Optionally provide a default strategy so clients that do not care about the choice are unaffected ```python # BEFORE (conditional in Context) class DataProcessor: def __init__(self, algorithm: str): self._algorithm = algorithm def process(self, data: list) -> list: if self._algorithm == "bubble": # bubble sort logic — 10 lines ... elif self._algorithm == "quick": # quicksort logic — 20 lines ... elif self._algorithm == "merge": # merge sort logic — 25 lines ... # AFTER (Strategy delegation) class DataProcessor: def __init__(self, strategy: SortStrategy = None): # Default strategy makes Strategy optional for clients self._strategy = strategy or BubbleSortStrategy() def set_strategy(self, strategy: SortStrategy) -> None: """Swap algorithm at runtime without reconstructing the context.""" self._strategy = strategy def process(self, data: list) -> list: return self._strategy.sort(data) ``` **Making Strategy optional:** If it is meaningful for the Context to have no strategy, check before delegating and execute default behavior when none is set. This keeps clients that do not need strategy selection from having to deal with Strategy objects at all. --- ### Step 5: Validate and Apply Optional Optimizations **ACTION:** Verify the refactoring is complete, then apply optimizations if warranted. **WHY:** The refactoring is only complete when the original conditional is fully gone and all variants are covered. Partial migration — leaving one branch in the Context "for now" — defeats the pattern and re-introduces the code smell. Validation catches this before new code is written against the incomplete structure. **Validation checklist:** - [ ] The original conditional block is entirely removed from the Context - [ ] Every branch of the original conditional has a corresponding ConcreteStrategy - [ ] The Context delegates to the strategy via the interface — it imports no ConcreteStrategy class directly - [ ] Each ConcreteStrategy can be instantiated and tested independently - [ ] Adding a new algorithm requires only a new class, not a change to the Context **Optional optimizations:** | Optimization | When to apply | |--------------|--------------| | **Flyweight sharing** | ConcreteStrategies are stateless — share one instance across all Contexts instead of allocating per-Context | | **Default strategy** | Most clients use one algorithm — set it as default so callers who do not care are unaffected | | **Factory for selection** | Strategy selection logic is complex — extract it into a factory rather than leaving it scattered in callers | | **Abstract base with shared logic** | Multiple ConcreteStrategies share common steps — add a base ConcreteStrategy class with shared implementation (not the interface) | **Drawback awareness — address before finishing:** - **Client awareness:** Clients must now know which ConcreteStrategy to instantiate. If this knowledge is non-trivial (depends on configuration, environment, or runtime data), introduce a factory or builder to centralize selection logic. - **Communication overhead:** The Strategy interface is shared by all ConcreteStrategies regardless of complexity. Simple strategies may receive parameters they do not use (e.g., `ArrayCompositor` in the Lexi case ignores stretchability data). If this overhead is significant, consider tighter coupling between specific strategies and the context — but accept that this reduces generality. --- ## Examples ### Example 1: Payment Processing (Classic Conditional to Strategy) **Scenario:** An e-commerce checkout has a `PaymentService` with a large `if/else` chain selecting between credit card, PayPal, and bank transfer logic. A new payment method is requested every quarter, and each addition requires modifying `PaymentService` directly. **Trigger:** "Every time we add a payment provider, we touch the same `process_payment` method and it keeps growing." **Before (the code smell):** ```python class PaymentService: def process_payment(self, amount: float, method: str, details: dict): if method == "credit_card": # validate card, charge via Stripe, handle 3DS... elif method == "paypal": # OAuth flow, PayPal API call, webhook... elif method == "bank_transfer": # IBAN validation, SEPA/ACH routing... else: raise ValueError(f"Unknown method: {method}") ``` **After (Strategy):** ```python class PaymentStrategy: def process(self, amount: float, details: dict) -> PaymentResult: raise NotImplementedError class CreditCardStrategy(PaymentStrategy): def process(self, amount: float, details: dict) -> PaymentResult: # Stripe integration, 3DS, card validation class PayPalStrategy(PaymentStrategy): def process(self, amount: float, details: dict) -> PaymentResult: # OAuth, PayPal API, webhook handling class BankTransferStrategy(PaymentStrategy): def process(self, amount: float, details: dict) -> PaymentResult: # IBAN validation, SEPA/ACH routing class PaymentService: def __init__(self, strategy: PaymentStrategy): self._strategy = strategy def process_payment(self, amount: float, details: dict) -> PaymentResult: return self._strategy.process(amount, details) # Caller selects the strategy — PaymentService never changes service = PaymentService(CreditCardStrategy()) result = service.process_payment(99.99, {"card_number": "..."}) ``` **Output:** `PaymentService` is closed to modification. Adding `CryptoStrategy` requires zero changes to existing code. --- ### Example 2: Lexi Document Formatter (GoF Case Study) **Scenario:** Lexi, a WYSIWYG document editor, must break text into lines. Several algorithms exist: a simple greedy line-breaker, a full TeX-quality algorithm optimizing paragraph-level color, and a fixed-interval breaker for icon grids. The algorithms have different speed-quality trade-offs and the user may switch between them. **Trigger:** "The formatting algorithm needs to change at runtime depending on document type, and we need to add new algorithms without touching the document structure." **Design (from GoF, pages 48-50 and 296-298):** ``` Context: Composition (holds content glyphs, line width) Strategy: Compositor (abstract — Compose() interface) ConcreteA: SimpleCompositor — greedy, line-at-a-time, fast ConcreteB: TeXCompositor — paragraph-at-a-time, optimizes whitespace color ConcreteC: ArrayCompositor — fixed interval, for icon grids ``` The Compositor interface takes all layout data as explicit parameters (Approach 1 — data to the strategy): ```cpp virtual int Compose( Coord natural[], Coord stretch[], Coord shrink[], int componentCount, int lineWidth, int breaks[] ) = 0; ``` This interface is wide enough to support all three algorithms. `SimpleCompositor` ignores stretchability; `ArrayCompositor` ignores everything except component count. This is the **communication overhead trade-off** — some ConcreteStrategies receive data they do not use. The GoF accept this because the alternative (passing `this` as a context reference) would couple Compositor subclasses to Composition's full interface. **Runtime swap:** ```cpp // Switching quality at runtime — no reconstruction of Composition composition->SetCompositor(new TeXCompositor()); composition->Repair(); // delegates to compositor->Compose(...) ``` **Output:** Adding a new linebreaking algorithm is a new `Compositor` subclass. Neither `Composition` nor the glyph classes are ever modified. --- ### Example 3: Report Exporter with Runtime Selection **Scenario:** A reporting tool exports data as CSV, JSON, or PDF. The format is determined by user selection at runtime. Currently the export logic lives in a single `export()` method with a `format` string parameter driving a conditional. **Trigger:** "Users can choose the export format from a dropdown — the format isn't known until they click Export." **Strategy interface (data to strategy, Approach 1):** ```python class ExportStrategy: def export(self, records: list[dict], output_path: str) -> None: raise NotImplementedError class CsvExportStrategy(ExportStrategy): def export(self, records, output_path): import csv with open(output_path, "w", newline="") as f: writer = csv.DictWriter(f, fieldnames=records[0].keys()) writer.writeheader() writer.writerows(records) class JsonExportStrategy(ExportStrategy): def export(self, records, output_path): import json with open(output_path, "w") as f: json.dump(records, f, indent=2) class PdfExportStrategy(ExportStrategy): def export(self, records, output_path): # reportlab or weasyprint integration ... class ReportExporter: _STRATEGIES = { "csv": CsvExportStrategy, "json": JsonExportStrategy, "pdf": PdfExportStrategy, } def __init__(self): self._strategy: ExportStrategy = CsvExportStrategy() # default def set_format(self, format_key: str) -> None: """Runtime swap — called when user selects format in UI.""" cls = self._STRATEGIES.get(format_key) if not cls: raise ValueError(f"Unknown format: {format_key}") self._strategy = cls() def export(self, records: list[dict], output_path: str) -> None: self._strategy.export(records, output_path) ``` **Key decision:** The `_STRATEGIES` registry centralizes selection logic in the Context, keeping callers simple. An alternative is to move this registry to a factory, which is preferable when selection logic becomes complex (e.g., involving feature flags or user tier). **Output:** The UI dropdown maps to `set_format()`. Adding XML export is a new `XmlExportStrategy` class plus one entry in `_STRATEGIES` — the rest of the system is unchanged. --- ## Strategy vs. Template Method — When to Use Which Both patterns encapsulate algorithmic variation. The choice is **composition vs. inheritance**: | Dimension | Strategy | Template Method | |-----------|----------|----------------| | Mechanism | Composition — context holds a strategy object | Inheritance — subclass overrides abstract steps | | Runtime swap | Yes — install a different strategy object | No — fixed at class definition | | Granularity | Entire algorithm is replaced | Only specific steps are replaced; skeleton is fixed | | Class count | One class per algorithm variant | One subclass per algorithm variant | | Coupling | Strategy and Context are loosely coupled | Subclass is tightly coupled to superclass skeleton | | Evolution path | Start with Template Method → migrate to Strategy when inheritance becomes limiting | — | **Choose Strategy when** the algorithm must be swappable at runtime, when you do not control the class hierarchy, or when the number of variants is large and growing. **Choose Template Method when** the algorithm skeleton is fixed and only specific steps vary, and when compile-time binding is acceptable. --- ## Reference Files | File | Contents | |------|----------| | `references/strategy-implementation-guide.md` | Participants, full consequences catalog, interface design decision tree, Flyweight optimization, language-specific notes | ## License This skill is licensed under [CC-BY-SA-4.0](https://creativecommons.org/licenses/by-sa/4.0/). Source: [BookForge](https://github.com/bookforge-ai/bookforge-skills) — Design Patterns: Elements of Reusable Object-Oriented Software by Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides. ## Related BookForge Skills Install related skills from ClawhHub: - `clawhub install bookforge-behavioral-pattern-selector` Or install the full book set from GitHub: [bookforge-skills](https://github.com/bookforge-ai/bookforge-skills)

path: references/strategy-implementation-guide.md
content: # Strategy Pattern — Implementation Guide

Full reference for the `strategy-pattern-implementor` skill. Contains the complete participants catalog, all 7 consequences, the interface design decision tree, Flyweight optimization details, and language-specific implementation notes.

---

## Participants

### Strategy (e.g., `Compositor`, `SortStrategy`, `PaymentStrategy`)
- Declares an interface common to all supported algorithms
- Context uses this interface exclusively — it never imports a ConcreteStrategy directly
- The interface method signature is the central design decision (see Interface Design section below)

### ConcreteStrategy (e.g., `SimpleCompositor`, `TeXCompositor`, `QuickSortStrategy`)
- Implements the algorithm using the Strategy interface
- Each class encapsulates one algorithm and its algorithm-specific data
- ConcreteStrategies do not know about each other (unlike State, where state objects may initiate transitions to siblings)

### Context (e.g., `Composition`, `DataProcessor`, `PaymentService`)
- Configured with a ConcreteStrategy object at construction or via a setter
- Maintains a reference to a Strategy object
- May define an interface that lets Strategy access its data (relevant for Approach 2 — passing context as argument)
- Forwards algorithm execution to the Strategy; does not implement the algorithm itself

---

## Collaborations

- Strategy and Context interact to implement the chosen algorithm
- A context may pass all required data to the strategy when the algorithm is called (Approach 1), or pass itself as an argument and let the strategy request what it needs (Approach 2)
- Clients usually create and pass a ConcreteStrategy object to the context; thereafter, clients interact with the context exclusively
- There is often a family of ConcreteStrategy classes for a client to choose from — a factory or registry can centralize this selection

---

## All 7 Consequences

### Benefits

**1. Families of related algorithms**
Strategy hierarchies define a reusable family of algorithms or behaviors. Inheritance can factor out common functionality of the algorithms into a shared base ConcreteStrategy class (not the interface). This keeps common logic out of both the Context and the individual concrete implementations.

**2. An alternative to subclassing**
Without Strategy, you would subclass the Context directly to give it different behaviors (e.g., `BubbleSortDataProcessor`, `QuickSortDataProcessor`). This hard-wires the algorithm into the Context: it mixes algorithm implementation with Context logic, makes Context harder to understand and extend, and prevents runtime algorithm swapping. You end up with many related subclasses whose only difference is the algorithm they employ. Strategy via composition avoids all of this.

**3. Strategies eliminate conditional statements**
When different behaviors are lumped into one class, conditional statements to select the right behavior are unavoidable. Encapsulating behaviors in separate Strategy classes eliminates these conditionals entirely.

Example — without Strategy (the code smell):
```cpp
void Composition::Repair() {
    switch (_breakingStrategy) {
    case SimpleStrategy:
        ComposeWithSimpleCompositor();
        break;
    case TeXStrategy:
        ComposeWithTeXCompositor();
        break;
    // ...
    }
    // merge results with existing composition, if necessary
}
```

With Strategy (the refactored form):
```cpp
void Composition::Repair() {
    _compositor->Compose();
    // merge results with existing composition, if necessary
}
```

Code containing many conditional statements often indicates the need to apply the Strategy pattern.

**4. A choice of implementations**
Strategies can provide different implementations of the same behavior. The client can choose among strategies with different time and space trade-offs — for example, a fast-but-approximate algorithm vs. a slower but globally optimal one (SimpleCompositor vs. TeXCompositor).

### Drawbacks

**5. Clients must be aware of different Strategies**
The pattern has a potential drawback: a client must understand how Strategies differ before it can select the appropriate one. Clients may be exposed to implementation details. Therefore, use Strategy only when the variation in behavior is relevant to clients. If clients do not care about algorithm selection and a sensible default exists, provide a default strategy so they never have to deal with strategy objects at all.

**6. Communication overhead between Strategy and Context**
The Strategy interface is shared by all ConcreteStrategy classes whether the algorithms they implement are trivial or complex. Hence it is likely that some ConcreteStrategies will not use all the information passed to them through this interface — simple ConcreteStrategies may use none of it.

In the Lexi case, `SimpleCompositor` ignores stretchability data; `ArrayCompositor` ignores everything. This means the context creates and initializes parameters that never get used. If this overhead is an issue, tighter coupling between Strategy and Context is needed — but this reduces the generality of the pattern.

**7. Increased number of objects**
Strategies increase the number of objects in an application. Sometimes you can reduce this overhead by implementing strategies as stateless objects that contexts can share (see Flyweight Optimization below). Any residual state is maintained by the context, which passes it in each request to the Strategy object.

---

## Interface Design Decision Tree

Use this to choose between Approach 1 (pass data as parameters) and Approach 2 (pass context reference):

```
Does the strategy need a bounded, well-known set of inputs?
├── YES → Use Approach 1: explicit parameters
│         Keeps Strategy and Context decoupled.
│         Context passes data[], counts, and output buffers.
│         Risk: some ConcreteStrategies receive parameters they don't use.
│
└── NO → Does the data set vary significantly across ConcreteStrategies?
         ├── YES → Use Approach 2: pass context as argument
         │         Strategy calls back on the context to get what it needs.
         │         Context must expose a richer interface to its data.
         │         Risk: tighter coupling between Strategy and Context.
         │
         └── Can Strategy store a reference to Context at construction?
                  YES → Initialize strategy with context reference.
                        Eliminates per-call parameter passing entirely.
                        Strategy can request exactly what it needs on demand.
                        Risk: tightest coupling — Strategy is bound to one Context type.
```

**General rule:** The needs of the particular algorithm and its data requirements determine the best technique. Prefer Approach 1 when parameters are bounded and stable. Move to Approach 2 when parameter lists grow unwieldy or vary significantly across strategies.

---

## Flyweight Optimization

Strategies increase object count. When strategies are stateless — all working data comes from parameters, nothing is stored between calls — they can be shared as Flyweights:

**When it applies:**
- The ConcreteStrategy has no instance variables
- All state is passed in via the interface method parameters
- The same algorithm is used by many Context instances simultaneously

**When it does NOT apply:**
- The ConcreteStrategy stores configuration (e.g., `ArrayCompositor` stores an interval count — this is constructor-injected state, not per-invocation state, but it makes the strategy non-shareable unless all contexts want the same interval)
- The algorithm accumulates state across multiple invocations

**Implementation pattern:**

```python
# Stateless strategy — safe to share
class JsonExportStrategy(ExportStrategy):
    # No instance variables — all data comes through export()
    def export(self, records, output_path):
        import json
        with open(output_path, "w") as f:
            json.dump(records, f, indent=2)

# Shared instance registry — one object per algorithm
class StrategyRegistry:
    _instances: dict[str, ExportStrategy] = {}

    @classmethod
    def get(cls, key: str) -> ExportStrategy:
        if key not in cls._instances:
            cls._instances[key] = _STRATEGY_CLASSES[key]()
        return cls._instances[key]
```

Shared strategies should not maintain state across invocations. The Flyweight pattern (GoF p. 195) describes this approach in detail.

---

## Making Strategy Optional

The Context class can be simplified when it is meaningful to have no strategy. The Context checks for a strategy before delegating; if none is set, it executes default behavior:

```python
class DataProcessor:
    def __init__(self, strategy: SortStrategy = None):
        self._strategy = strategy  # None is valid

    def process(self, data: list) -> list:
        if self._strategy is None:
            # Default behavior — no strategy object required
            return sorted(data)
        return self._strategy.sort(data)
```

The benefit: clients who are satisfied with the default behavior never need to deal with Strategy objects at all. Only clients that need non-default behavior need to know strategies exist.

---

## Strategy as Template Parameters (C++ / Generics)

In statically typed languages with generics, Strategy can be expressed as a template/generic parameter rather than a runtime interface:

```cpp
template <class AStrategy>
class Context {
    void Operation() { theStrategy.DoAlgorithm(); }
    // ...
private:
    AStrategy theStrategy;
};

// Configured at compile time — no virtual dispatch overhead
Context<MyStrategy> aContext;
```

This approach is applicable only when:
1. The strategy is selected at compile time (not runtime)
2. It does not need to be changed at runtime

The benefit: static binding eliminates virtual dispatch overhead. Strategy and Context are bound at compile time — this can increase efficiency significantly in performance-critical code.

---

## Strategy vs. State — The Critical Distinction

Strategy and State have identical class diagrams. The difference is intent and who initiates the swap:

| Question | Strategy | State |
|----------|----------|-------|
| Who changes the behavior? | The **client** installs a strategy explicitly | The **context object** transitions itself based on internal logic |
| Do concrete variants know about each other? | No — strategies are independent | Yes — state objects often initiate transitions to sibling states |
| Is the variation about selecting an algorithm? | Yes — same interface, different computation | No — about representing a lifecycle that drives behavior |
| Can the same "strategy" be active indefinitely? | Yes | No — states have transition logic |

**Rule:** If the behavioral swap is driven by external selection (caller chooses the algorithm), it is Strategy. If the behavioral swap is driven by the object's internal state machine (the object decides when to change its own behavior), it is State.

---

## Known Uses

- **Lexi document editor (GoF case study):** `Composition`/`Compositor` — formatting algorithm encapsulated as interchangeable Compositor strategies (SimpleCompositor, TeXCompositor, ArrayCompositor)
- **RTL compiler optimizer:** `RegisterAllocator` and `RISCScheduler`/`CISCScheduler` — register allocation and instruction scheduling as strategies, enabling retargeting to different machine architectures
- **ObjectWindows dialog validation:** `Validator` objects encapsulate field validation strategies (`RangeValidator`, custom validators) — attached optionally to entry fields
- **ET++SwapsManager:** Financial instrument pricing strategies — `YieldCurve` subclasses encapsulate discount factor computation strategies, mixed and matched per instrument type
- **Java `Comparator`:** `Collections.sort(list, comparator)` — the Comparator is a Strategy object encapsulating the comparison algorithm
- **Python `key=` parameter in `sorted()`:** A function reference as a lightweight Strategy (first-class function as ConcreteStrategy, no subclass required)

---

## Language-Specific Notes

### Python
- First-class functions eliminate the need for explicit ConcreteStrategy classes in simple cases: `processor.set_strategy(lambda data: sorted(data))` is a valid Strategy
- Use `abc.ABC` and `@abstractmethod` for the Strategy interface to enforce implementation at class-definition time
- Stateless strategies can be module-level singletons (avoid repeated instantiation)

### Java
- Use an interface (not abstract class) for the Strategy unless shared implementation is needed
- Java lambdas (single-method functional interfaces) make lightweight strategies trivial: `sorter.setStrategy(data -> Arrays.sort(data))`
- `java.util.Comparator` is the canonical Strategy in the standard library

### TypeScript / JavaScript
- Strategy interface expressed as a TypeScript interface or type alias with a single call signature
- Functions as strategies are idiomatic: `context.setStrategy((data) => data.sort())`

### Go
- Strategy interface is a Go interface — implicit implementation, no declaration required
- Structs implementing the interface are ConcreteStrategies
- Function types can serve as lightweight strategies for single-method interfaces


Security scan verdicts — ClawScan: clean | static analysis: clean | VirusTotal: clean | SkillSpector: clean (LOW)