Behavioral Design Patterns
What Are Behavioral Patterns?β
Behavioral patterns deal with how objects communicate and distribute responsibility. While creational patterns focus on building objects and structural patterns on composing them, behavioral patterns focus on how they interact β who does what, and how messages flow between collaborators.
Why They Matterβ
| Problem | Pattern That Solves It |
|---|---|
| Need to swap algorithms at runtime | Strategy |
| One object's state change should notify many others | Observer |
| Need to encapsulate a request as an object (undo, queue, log) | Command |
| Need to traverse a collection without exposing its structure | Iterator |
| Objects should communicate without knowing about each other directly | Mediator |
| Define an algorithm skeleton, let subclasses override steps | Template Method |
| Multiple handlers should process a request in order | Chain of Responsibility |
| Object's behavior should change based on its internal state | State |
| Add operations to object structures without modifying the types | Visitor |
The Coffee Shop Domainβ
All examples continue with the Coffee Shop domain. We build on the same model:
public abstract class Coffee
{
public string Name { get; init; } = "";
public double Price { get; init; }
public List<string> Ingredients { get; init; } = new();
public CupSize Size { get; init; } = CupSize.Medium;
public override string ToString() =>
$"{Name} ({Size}) β ${Price:F2} [{string.Join(", ", Ingredients)}]";
}
public enum CupSize { Small, Medium, Large }
Pattern Comparisonβ
| Pattern | Intent | When to Use |
|---|---|---|
| Strategy | Encapsulate interchangeable algorithms | Pricing, sorting, compression strategies |
| Observer | One-to-many dependency with automatic notification | Events, pub/sub, UI data binding |
| Command | Encapsulate a request as an object | Undo/redo, task queues, macro recording |
| Iterator | Sequential access without exposing internals | Collection traversal, LINQ, pagination |
| Mediator | Centralize communication between colleagues | UI dialog coordination, chat rooms, air traffic |
| Template Method | Algorithm skeleton with overridable steps | Frameworks, lifecycle hooks, data processing |
| Chain of Responsibility | Pass request along a chain of handlers | Middleware, validation pipelines, logging |
| State | Behavior changes with internal state | Vending machines, order status, game characters |
| Visitor | Add operations to a structure without changing it | AST processing, report generation, serialization |
Common Pitfallsβ
- Observer memory leaks: Forgetting to unsubscribe observers. In C#, use weak events or explicitly detach.
- Mediator becoming a god object: The mediator coordinates, not contains business logic. Keep it thin.
- Template Method and Hollywood Principle: Don't call us, we'll call you. Base class calls overrides, not the other way around.
- Chain of Responsibility with no terminator: If no handler processes the request, it silently disappears. Always have a catch-all.
Related Topicsβ
- SOLID Principles β behavioral patterns heavily rely on SRP and OCP
- Delegates & Events β C# language features that implement Observer natively
- Creational Patterns β how to create the objects
- Structural Patterns β how to compose the objects