Structural Pattern Distinctions and Behavioral Patterns: Chain of Responsibility & Command
This section covers two major topics from the Gang of Four: first, the nuanced distinctions between structurally similar patterns (Adapter vs Bridge, Composite vs Decorator vs Proxy), and second, the introduction to Behavioral Patterns with full coverage of Chain of Responsibility and the beginning of Command. The structural comparisons clarify when superficially similar patterns serve fundamentally different intents. The behavioral patterns shift focus from object composition to algorithms, responsibilities, and communication between objects.
Key Concepts
Structural Pattern Distinctions:
Adapter vs Bridge: Adapter makes things work *after* they're designed (unforeseen coupling); Bridge makes them work *before* they are (planned abstraction/implementation separation). Adapter reuses an old interface; Facade defines a new one.
Composite vs Decorator: Both use recursive composition but differ in intent. Decorator adds responsibilities without subclassing (avoids subclass explosion). Composite structures classes so many related objects are treated uniformly. They are complementary and often used together — from Decorator's view, a Composite is a ConcreteComponent; from Composite's view, a Decorator is a Leaf.
Decorator vs Proxy: Both compose an object and provide an identical interface. Decorator is for dynamically attaching/detaching properties via recursive composition. Proxy provides a stand-in for access control, remote access, or persistence — it focuses on one static relationship between proxy and subject. Proxy is not designed for recursive composition.
Hybrid combinations (proxy-decorator, decorator-proxy) are possible but decompose into the individual patterns.
Behavioral Patterns Overview:
Concerned with algorithms and assignment of responsibilities between objects
Characterize complex control flow that's hard to follow at runtime
Behavioral class patterns use inheritance: Template Method (simpler, more common) and Interpreter
Behavioral object patterns use composition: Mediator, Chain of Responsibility, Observer, Strategy, Command, State, Visitor, Iterator
Chain of Responsibility:
Avoids coupling sender to receiver by giving multiple objects a chance to handle a request
Request passes along a chain until an object handles it — the request has an *implicit receiver*
The sender has no knowledge of which object will handle the request
Participants: Handler (defines interface, optionally implements successor link), ConcreteHandler (handles requests it's responsible for, forwards others), Client (initiates request)
Command:
Encapsulates a request as an object, enabling parameterization, queuing, logging, and undo
Also known as Action or Transaction
Key abstraction: an abstract Command class with an Execute operation
Concrete Command subclasses store a receiver and implement Execute to invoke operations on it
MacroCommand sequences multiple commands with no explicit receiver
Commands are the object-oriented replacement for callbacks
Chain of Responsibility — Widget hierarchy with help:
class Widget : public HelpHandler {
protected:
Widget(Widget* parent, Topic t = NO_HELP_TOPIC);
private:
Widget* _parent;
};
class Button : public Widget {
public:
Button(Widget* d, Topic t = NO_HELP_TOPIC);
virtual void HandleHelp();
};
void Button::HandleHelp() {
if (HasHelp()) {
// offer help on the button
} else {
HelpHandler::HandleHelp(); // forward to successor
}
}
Application* application = new Application(APPLICATION_TOPIC);
Dialog* dialog = new Dialog(application, PRINT_TOPIC);
Button* button = new Button(dialog, PAPER_ORIENTATION_TOPIC);
button->HandleHelp(); // starts chain traversal
Relationships
Chain of Responsibility + Composite: Often applied together — a component's parent acts as its successor in the chain
Adapter vs Bridge vs Facade: Adapter reuses existing interfaces post-design; Bridge separates abstraction from implementation pre-design; Facade defines a new simplified interface
Composite + Decorator: Complementary — can build applications by plugging objects together without new classes; share a common interface when used together
Decorator + Proxy: Structurally similar but different intents; can be hybridized (proxy-decorator, decorator-proxy)
Template Method vs Strategy: Template Method uses inheritance to vary parts of an algorithm; Strategy uses composition to encapsulate entire algorithms
Mediator vs Chain of Responsibility vs Observer: All address object communication — Mediator centralizes it, Chain of Responsibility passes along a chain, Observer broadcasts to dependents
Command + Composite: MacroCommand is essentially a Composite of commands
Command: Connects to Chain of Responsibility when commands are forwarded through a hierarchy (as in Unidraw's Component/Command interpretation)
Exam-Relevant Points
Adapter works after design; Bridge works before design — this is the key lifecycle distinction
Facade defines a NEW interface; Adapter reuses an OLD interface — common trick question
Composite and Decorator have similar structure diagrams but completely different intents (representation vs embellishment)
Proxy focuses on one static relationship; Decorator uses recursive composition for open-ended functionality
Chain of Responsibility's key consequence: receipt is NOT guaranteed — requests can fall off the chain unhandled
Chain of Responsibility provides reduced coupling (objects keep only a single successor reference) and flexibility (chain can be reconfigured at runtime)
Three ways to represent requests in Chain of Responsibility: (1) hard-coded operations, (2) request codes with a single handler function, (3) request objects (most flexible/type-safe)
Existing object references (e.g., parent references in a part-whole hierarchy) can serve as the successor chain — no need to define new links
Smalltalk's doesNotUnderstand can implement automatic forwarding in Chain of Responsibility
Command pattern's key use cases: parameterize objects with actions, queue/log requests, support undo/redo
Commands are the OO replacement for callbacks
MacroCommand sequences commands and has no explicit receiver — commands define their own receivers
Command enables both menu and push-button interfaces to share the same concrete Command instance
For undo: Command stores state, interface adds Unexecute, executed commands go on a history list; traversing backwards/forwards gives unlimited undo/redo