Discussion of Behavioral Patterns and the Role of Design Patterns in Software Design
This section synthesizes the behavioral pattern catalog by identifying cross-cutting themes — encapsulating variation, objects as arguments, communication topology — and then compares four patterns that decouple senders from receivers. Chapter 6 reflects on what design patterns accomplish: a shared vocabulary, a documentation aid, a complement to design methods, and a target for refactoring. It traces the history of the GoF catalog and situates it within the broader pattern community originating from Christopher Alexander's architectural work.
Key Concepts
Encapsulating Variation: The central theme of behavioral patterns — isolate the aspect that changes into a dedicated object:
Strategy encapsulates an algorithm
State encapsulates state-dependent behavior
Mediator encapsulates inter-object protocol
Iterator encapsulates traversal of an aggregate
Objects as Arguments: Some patterns define objects passed as arguments rather than partitioning functionality:
Visitor is passed as an argument to Accept
Command represents a request as a token object
Memento represents internal state as a token object
Command tokens are polymorphic; Memento tokens have a narrow interface with no polymorphic operations
Mediator vs. Observer — competing patterns for communication:
Observer distributes communication (loose coupling, finer-grained, more reusable classes)
Mediator centralizes communication (easier to understand flow, but harder to reuse)
In Smalltalk, Observer is preferred because observers can be parameterized with messages; in C++, Mediator is often preferred
Decoupling Senders and Receivers — four approaches with different trade-offs:
Command: defines binding in a separate object; sender works with different receivers; nominally one subclass per connection
Observer: looser binding; subject may have multiple observers varying at runtime; best when there are data dependencies
Mediator: indirect reference through mediator; centralizes communication; may reduce subclassing but can decrease type safety via ad hoc dispatching
Chain of Responsibility: passes request along a chain; good when chain is part of existing structure; also may require custom dispatching with type-safety drawbacks
Pattern Synergy: Patterns reinforce each other — Chain of Responsibility uses Template Method; Interpreter uses State; Composite uses Visitor, Chain of Responsibility, Decorator, Observer, State, Builder, and Prototype together
Software Lifecycle Phases (Brian Foote): prototyping → expansionary → consolidating (refactoring), cycling between expansion and consolidation
White-box vs. Black-box Reuse Evolution: Early systems rely on inheritance (white-box); refactoring moves toward composition (black-box)
Design Patterns as Refactoring Targets: Patterns capture structures that result from refactoring; applying them early prevents later refactoring; applying them late guides how to change
Comparison with Alexander: Both observe existing systems, use templates and natural language. Differences: Alexander orders patterns and claims they generate complete buildings; GoF does not claim completeness and focuses more on solutions than problems
Commands and Syntax
No commands or code syntax in this section — it is a conceptual discussion and conclusion.
Relationships
Strategy, State, Mediator, Iterator — all exemplify encapsulating variation; each encapsulates a different aspect (algorithm, behavior, protocol, traversal)
Visitor, Command, Memento — objects used as arguments; differ in polymorphism expectations
Mediator vs. Observer — competing alternatives for inter-object communication; choice depends on reusability vs. comprehensibility needs
Command, Observer, Mediator, Chain of Responsibility — four alternative approaches to sender-receiver decoupling
Chain of Responsibility + Template Method — chain handlers typically use Template Method internally
Composite + Visitor + Chain of Responsibility + Decorator + Observer + State + Builder + Prototype — commonly composed together in well-designed systems
Know the four sender-receiver decoupling patterns and their trade-offs: Command (separate binding object), Observer (one-to-many data dependencies), Mediator (centralized routing, reduced subclassing but less type safety), Chain of Responsibility (chain-based, flexible but also less type safe)
Mediator vs. Observer: Observer produces more reusable but harder-to-trace classes; Mediator is easier to follow but harder to reuse. Language matters: Smalltalk favors Observer, C++ favors Mediator
Command vs. Memento: Both are token objects, but Command is polymorphic (Execute operation); Memento has a narrow, non-polymorphic interface
Encapsulating variation is THE unifying theme of behavioral patterns — expect questions mapping specific patterns to what they encapsulate
Chain of Responsibility is unique among behavioral patterns: it doesn't partition functionality into new/existing objects, and it doesn't define static communication relationships
Design patterns are NOT a complete pattern language — they are a collection of related patterns, not step-by-step instructions for designing an application
Patterns provide a common vocabulary that raises the level of design discussion beyond notation and programming language
Patterns complement but do not replace design methods — they capture the "why" of design decisions that methods alone cannot
Patterns as refactoring targets: using patterns early prevents refactoring; recognizing them later guides refactoring direction