Structural & Behavioral Patterns
In a Nutshell
Beyond creating objects, design patterns address two other recurring concerns. Structural patterns deal with how objects and classes are composed into larger structures — how to combine pieces so the whole is flexible and the relationships are clean (Adapter, Decorator, Facade, Proxy, Composite). Behavioral patterns deal with how objects communicate and share responsibility — how they interact, distribute work, and respond to events (Observer, Strategy, Command, Iterator, State). Where creational patterns answer "how do I make objects?", structural patterns answer "how do I assemble them?" and behavioral patterns answer "how do they collaborate?" These patterns are the vocabulary of good object-oriented design and appear constantly in real systems.

How It Actually Works
Structural Patterns: Composing Objects
| Pattern | Problem It Solves | One-Liner |
|---|---|---|
| Adapter | Two incompatible interfaces need to work together | Wrap one interface to look like another |
| Decorator | Add behavior without subclassing | Wrap an object to extend it dynamically |
| Facade | A complex subsystem is hard to use | A simple front door to a complex system |
| Proxy | Control access to an object | A stand-in that adds control (lazy load, auth, cache) |
| Composite | Treat individual and grouped objects uniformly | A tree where leaves and branches share an interface |
Adapter bridges incompatible interfaces (wrap a third-party library to match your interface). Decorator adds behavior by wrapping (add logging/caching/compression around a component without changing it). Facade hides complexity behind a simple interface (a single OrderService.placeOrder() fronting inventory, payment, and shipping subsystems). Proxy stands in for an object to add control (lazy loading, access control, caching — the caching and service mesh sidecar are proxy-pattern applications).
Behavioral Patterns: Coordinating Objects
| Pattern | Problem It Solves | One-Liner |
|---|---|---|
| Observer | Many objects need to react to a state change | Publish state changes to subscribers |
| Strategy | Swap algorithms at runtime | Encapsulate interchangeable algorithms |
| Command | Encapsulate a request as an object | Requests become objects (queue, undo, log them) |
| Iterator | Traverse a collection without exposing internals | Sequential access without knowing the structure |
| State | Behavior changes with internal state | An object behaves differently per state |
Observer is the OOP root of pub/sub — subjects notify subscribers of changes (event listeners, reactive UIs). Strategy encapsulates interchangeable algorithms behind a common interface so you can swap them at runtime (different pricing, sorting, or routing strategies chosen by config). Command turns a request into an object you can queue, log, or undo (the basis of task queues and undo systems). State lets an object change behavior as its state changes (the circuit breaker is a state machine).
Strategy: The Workhorse Behavioral Pattern
Strategy is worth a closer look because it's everywhere and embodies "composition over inheritance":
# Instead of subclasses or if/else chains for each algorithm:
class ShippingCalculator:
def __init__(self, strategy):
self.strategy = strategy # inject the algorithm
def cost(self, order):
return self.strategy.calculate(order)
# Interchangeable strategies behind one interface:
calc = ShippingCalculator(ExpressShipping()) # swap at runtime
calc = ShippingCalculator(StandardShipping()) # or by config
This replaces sprawling conditionals with pluggable, testable, independently-evolving algorithms — the same idea behind swappable load-balancing algorithms and eviction policies.
Patterns Are a Vocabulary, Not a Checklist
The real value of patterns is shared vocabulary and proven structure — saying "wrap it in a decorator" or "use a strategy here" communicates a whole design instantly. But patterns can be over-applied: forcing patterns where a simple function suffices adds needless indirection. Use them when they solve a real problem (flexibility, decoupling, clarity), not to demonstrate cleverness.

Seeing It in Action
Scenario: Applying structural and behavioral patterns in a data-processing service.
# STRUCTURAL — Decorator: compose cross-cutting behavior around a data source
# Each wrapper adds one concern; the interface stays identical.
source = FileDataSource("data.bin")
source = CompressionDecorator(source) # transparently compress/decompress
source = EncryptionDecorator(source) # transparently encrypt/decrypt
source = CachingDecorator(source) # transparently cache reads
source.read() # flows through cache → decrypt → decompress → file
# Add/remove/reorder concerns by changing the wrapping — no core edits.
# STRUCTURAL — Facade: hide a complex subsystem behind one simple call
class OrderFacade:
def place_order(self, cart):
self.inventory.reserve(cart) # three subsystems coordinated
self.payment.charge(cart) # behind ONE simple method the
self.shipping.schedule(cart) # caller can use without knowing them
# Callers do OrderFacade().place_order(cart) — complexity hidden.
# BEHAVIORAL — Strategy: swap the processing algorithm at runtime/config
processor = DataProcessor(strategy=BatchStrategy()) # or StreamStrategy()
processor.run(dataset) # algorithm is pluggable and independently testable
# BEHAVIORAL — Observer: notify many subscribers of an event (pub/sub roots)
pipeline.on_complete.subscribe(send_notification) # each subscriber reacts
pipeline.on_complete.subscribe(update_dashboard) # independently to the
pipeline.on_complete.subscribe(trigger_next_job) # same "job done" event
# Why each pattern earns its place:
# Decorator: layer compression/encryption/caching in any combination without
# touching the core source or writing 2^N subclasses.
# Facade: give callers a simple entry point to a genuinely complex flow.
# Strategy: switch batch vs stream processing by config; test each alone.
# Observer: decouple the event producer from an open set of reactors —
# the OOP foundation of the pub/sub you'd use at system scale.
Why structural and behavioral patterns matter: these patterns are the concrete, object-level expression of the same principles that govern good system design at scale — and recognizing that connection is what makes them valuable rather than academic. Structural patterns are about composition: the Decorator lets you layer independent concerns (compression, encryption, caching) around a component in any combination without an explosion of subclasses or edits to the core — the same "wrap to add behavior transparently" idea behind a caching proxy or a service-mesh sidecar. The Facade tames complexity by giving callers one clean entry point to a subsystem, exactly as an API gateway fronts many services. Behavioral patterns are about collaboration: the Strategy pattern replaces sprawling conditionals with pluggable, independently-testable algorithms (batch vs stream, this pricing rule vs that), the same shape as swappable load-balancing or eviction policies; and the Observer pattern — subjects notifying an open set of subscribers — is literally the object-level root of pub/sub messaging. The deeper lesson is that these patterns give you a shared vocabulary and proven structures for the two questions that dominate design after "how do I create objects?": how do I compose pieces cleanly, and how do they communicate without tight coupling? Used deliberately — where they solve a real problem of flexibility, decoupling, or clarity, and not forced in where a plain function would do — they make code more adaptable to the change that always comes.
Interview Questions
Q: What's the difference between structural and behavioral patterns? Hint: Structural patterns deal with how objects/classes are composed into larger structures — clean, flexible relationships (Adapter, Decorator, Facade, Proxy, Composite). Behavioral patterns deal with how objects communicate and distribute responsibility — interaction and collaboration (Observer, Strategy, Command, Iterator, State). Structural = "how do I assemble objects?"; behavioral = "how do they collaborate?" (Creational = "how do I create them?")
Q: Explain the Decorator pattern and its advantage over subclassing. Hint: Decorator wraps an object to add behavior dynamically while preserving the same interface, so wrappers can be stacked in any combination (compression + encryption + caching around a data source). Advantage over subclassing: you avoid a combinatorial explosion of subclasses for every combination of behaviors, add/remove concerns at runtime, and follow composition-over-inheritance — behavior is layered, not baked into a class hierarchy.
Q: What is the Strategy pattern and why is it useful? Hint: It encapsulates interchangeable algorithms behind a common interface and lets you select/swap them at runtime or by config (different shipping, pricing, sorting, routing algorithms). It replaces sprawling if/else conditionals with pluggable, independently-testable, independently-evolving algorithm objects — embodying composition over inheritance and the open/closed principle. The same idea underlies swappable load-balancing and cache-eviction policies.
Q: How does the Observer pattern relate to pub/sub messaging? Hint: Observer is the object-level root of pub/sub: a subject maintains a list of subscribers and notifies them of state changes, decoupling the producer from an open set of reactors. Pub/sub scales this idea across processes/services with a broker, but the core concept — publish an event, all interested subscribers react independently, publisher unaware of them — is identical. Event listeners and reactive UIs are Observer in the small.
Q: What's the risk of overusing design patterns, and how do you decide when to apply one? Hint: Forcing patterns where a simple function or class suffices adds needless indirection, abstraction, and cognitive load — complexity that doesn't pay for itself. Patterns are a vocabulary and proven structures, not a checklist to maximize. Apply one when it solves a real problem (flexibility to swap implementations, decoupling, taming genuine complexity, clarity), not to demonstrate cleverness. Prefer the simplest thing that works.
References
- Design Patterns (Gang of Four) — the original catalog
- Refactoring.Guru: Structural & Behavioral Patterns — clear examples of each
- Head First Design Patterns — approachable treatment
Dive Deeper
- Composition over inheritance — the principle behind Strategy and Decorator
- Patterns of Enterprise Application Architecture by Martin Fowler — patterns at application scale
- Game Programming Patterns by Robert Nystrom — patterns explained with vivid examples