Level 2 · 25 min
Behavioral Patterns I
Behavioral patterns are concerned with algorithms and the assignment of responsibilities between objects. They describe how objects communicate and divide responsibilities to accomplish a task.
Observer and Strategy
Observer defines a one-to-many dependency — when one object changes state, all dependents are notified. The subject maintains a list of observers and calls update() on each. Used in event systems, reactive programming, MVC (model notifies view). Strategy encapsulates a family of algorithms and makes them interchangeable — the client selects the algorithm at runtime without knowing its details. Eliminates large if/switch blocks.
State and Template Method
State allows an object to alter its behavior when its internal state changes — the object appears to change its class. Eliminates sprawling if/switch on state flags; each state is a class. Template Method defines the skeleton of an algorithm in a base class and lets subclasses override specific steps without changing the algorithm's structure — calls abstract hook methods. GoF defines State's intent as: "Allow an object to alter its behavior when its internal state changes. The object will appear to change its class." (Gamma et al., Design Patterns, p.305). The canonical GoF example is a TCPConnection object that behaves differently (Open, Send, Close operations) depending on whether it's in Established, Listening, or Closed state — state classes encapsulate all behavior for each mode. In real systems, Spring Statemachine and XState both implement this pattern at framework level. Template Method is equally pervasive: JUnit's TestCase.runTest() is a Template Method — setUp() and tearDown() are the hook methods subclasses override. Spring's AbstractController, JdbcTemplate's query/update methods, and Hibernate's Session lifecycle all follow Template Method to define fixed algorithmic skeletons with pluggable steps.
Command
Command encapsulates a request as an object. Benefits: parameterize clients with different requests, queue or log requests, support undo/redo (store executed commands and call undo()). In Spring's JdbcTemplate, each database operation is a command. In event sourcing, events are essentially commands.
Code example
// Strategy pattern: sorting algorithm selection
interface SortStrategy { void sort(List<Integer> data); }
class QuickSort implements SortStrategy { /* ... */ }
class MergeSort implements SortStrategy { /* ... */ }
class BubbleSort implements SortStrategy { /* ... */ }
class Sorter {
private SortStrategy strategy;
void setStrategy(SortStrategy s) { this.strategy = s; }
void sort(List<Integer> data) { strategy.sort(data); }
}
// State pattern: order lifecycle
interface OrderState {
void confirm(Order order);
void ship(Order order);
void cancel(Order order);
}
class DraftState implements OrderState {
public void confirm(Order o) { o.setState(new ConfirmedState()); }
public void ship(Order o) { throw new IllegalStateException("Cannot ship draft"); }
public void cancel(Order o) { o.setState(new CancelledState()); }
}