State, Strategy, and Template Method Patterns (GoF Behavioral Patterns)
This section covers implementation details and sample code for the State pattern (continued), the complete Strategy pattern, and the beginning of the Template Method pattern. All three are behavioral patterns from the Gang of Four catalog that deal with varying behavior—State through internal object state, Strategy through interchangeable algorithms, and Template Method through subclass-defined steps in a fixed algorithm skeleton.
Key Concepts
State Pattern (continued):
State object lifecycle trade-off: Create-on-demand and destroy (saves memory when states are rarely entered) vs. create-all-upfront and never destroy (avoids repeated instantiation costs when state changes are frequent)
Dynamic inheritance: Some delegation-based languages (e.g., Self) support changing an object's class at runtime, directly implementing State without explicit state objects
Table-driven vs. State pattern: Table-driven approaches focus on defining state transitions; the State pattern models state-specific *behavior*
State objects that maintain no local state can be shared as Singletons
The Context delegates all state-specific requests to the current State object and knows nothing about the protocol
Strategy Pattern:
Intent: Define a family of algorithms, encapsulate each one, and make them interchangeable
Also known as: Policy
Strategies eliminate conditional statements — replace switch/case on algorithm type with delegation to a Strategy object
Strategies provide an alternative to subclassing the Context — composition over inheritance for varying behavior
Drawback: Clients must understand differences between strategies to select the right one
Communication overhead: The Strategy interface must serve all ConcreteStrategies; simple ones may ignore most parameters
Stateless strategies can be shared across contexts (Flyweight)
Two data-passing approaches: (1) Context passes data as parameters to Strategy ("take the data to the strategy"), keeping them decoupled; (2) Context passes itself, letting Strategy pull what it needs but increasing coupling
Template parameter technique (C++): Strategy can be a compile-time template parameter when it doesn't need to change at runtime — avoids abstract class overhead
Optional strategies: Context can define default behavior when no Strategy is installed
Template Method Pattern:
Intent: Define the skeleton of an algorithm in an operation, deferring some steps to subclasses
The template method fixes the ordering of steps but lets subclasses vary individual steps
Hook operations: Points in the template method where subclasses may optionally extend behavior
Used to implement invariant algorithm parts once, factor common behavior to avoid duplication, and control subclass extension points
A "refactoring to generalize" technique: identify differences → separate into new operations → replace with template method calls
Commands and Syntax
State pattern — TCP Connection example (C++):
// Context class delegates to State
class TCPConnection {
void ActiveOpen() { _state->ActiveOpen(this); }
void Close() { _state->Close(this); }
// ... all requests forwarded to _state
TCPState* _state;
};
// State base class — default (no-op) implementations
class TCPState {
virtual void ActiveOpen(TCPConnection*) { }
virtual void Close(TCPConnection*) { }
protected:
void ChangeState(TCPConnection* t, TCPState* s) {
t->ChangeState(s);
}
};
// Concrete states implement transitions
void TCPClosed::ActiveOpen(TCPConnection* t) {
ChangeState(t, TCPEstablished::Instance());
}
void TCPEstablished::Close(TCPConnection* t) {
ChangeState(t, TCPListen::Instance());
}
Strategy pattern — Composition/Compositor example (C++):
// Strategy interface — "take the data to the strategy" approach
class Compositor {
virtual int Compose(
Coord natural[], Coord stretch[], Coord shrink[],
int componentCount, int lineWidth, int breaks[]
) = 0;
};
// Context delegates to Strategy
void Composition::Repair() {
breakCount = _compositor->Compose(
natural, stretchability, shrinkability,
componentCount, _lineWidth, breaks
);
}
// Client selects strategy at construction
Composition* quick = new Composition(new SimpleCompositor);
Composition* slick = new Composition(new TeXCompositor);
Composition* iconic = new Composition(new ArrayCompositor(100));
State objects are often Singletons (127) — when they hold no instance-specific data
Flyweight (195) explains when/how State and Strategy objects can be shared as stateless flyweights
State vs. Strategy: Both use composition to delegate behavior, but State transitions are driven by internal state changes; Strategy is chosen by the client
Strategy vs. Template Method: Strategy uses composition (object behavioral); Template Method uses inheritance (class behavioral). Strategy varies the *whole* algorithm; Template Method varies *steps* within a fixed skeleton
Coplien's Envelope-Letter idiom is related to State — both change object behavior at runtime, but State is more specifically focused on state-dependent behavior
Strategy eliminates conditionals that would otherwise select among behaviors — related to Replace Conditional with Polymorphism refactoring
Template Method calls primitive operations and hook operations — primitive operations are abstract (must override); hooks have default behavior (may override)
The Template Method pattern supports "refactoring to generalize" (Opdyke and Johnson) — factor differences into overridable operations
Exam-Relevant Points
State vs. table-driven: State pattern models state-specific *behavior*; table-driven approach models state *transitions*. This is a key distinction
State object creation trade-off: Create-on-demand saves memory; create-upfront avoids repeated instantiation when transitions are frequent
Strategy's also-known-as name is "Policy"
Strategy eliminates conditional statements — the classic before/after is switch-on-type → delegation to strategy object
Two approaches for Strategy-Context data flow: pass data as parameters (loose coupling, may pass unused data) vs. pass context reference (tight coupling, strategy pulls only what it needs)
Strategies as template parameters: Only works when strategy is fixed at compile time and doesn't need runtime changes. Eliminates the abstract class but loses dynamic flexibility
Optional strategies: Context checks for null strategy and falls back to default behavior — clients don't need to deal with strategies unless they want non-default behavior
Template Method intent: Define algorithm skeleton; defer steps to subclasses. The key word is "skeleton" — the structure is fixed, steps vary
Hook operations in Template Method permit extensions only at specific points — this is how the pattern *controls* subclass extensions
Known uses of Strategy: ET++ and InterViews (linebreaking), RTL compiler (register allocation, instruction scheduling), ObjectWindows (validation), Booch components (memory allocation as template strategies)
State subclasses with no local state should be Singletons — each state needs only one instance (as in the TCP example)
Strategy drawback: Clients must understand how strategies differ to choose — pattern should only be used when variation in behavior is relevant to clients