Structural Patterns I: Adapter & Facade
Design Patterns
Chapter 4 · Structural Patterns I: Adapter & Facade
Structural patterns compose already-created objects into larger structures — no more object creation, just how existing pieces fit together. This chapter covers two of the most common: making an incompatible interface work without changing it (Adapter), and simplifying access to a complex, many-part subsystem (Facade).
Adapter: Making an Incompatible Interface Work
Client code expects a simple pay(amount) interface. A legacy payment gateway exposes something genuinely different — different method name, different units, an extra required parameter:
checkout(LegacyPaymentGateway(), 49.99) directly raises a genuine AttributeError: 'LegacyPaymentGateway' object has no attribute 'pay'. The two pieces of code are individually correct — they simply don't speak the same interface.
An Adapter wraps the incompatible object and exposes exactly the interface the client expects, translating each call underneath:
checkout(PaymentGatewayAdapter(LegacyPaymentGateway()), 49.99) — the identical checkout() function, completely unmodified — now succeeds, returning 'Legacy gateway charged 4999 cents (USD)'. 49.99 dollars correctly became 4999 cents — the conversion the adapter exists to handle, confirmed correct rather than assumed.
Facade: Simplifying a Complex Subsystem
Watching a movie on a real home theater setup means correctly sequencing three separate components — an amplifier, a projector, a DVD player — each with their own multi-step interface:
A Facade hides that entire sequence behind one method:
6 calls, in a specific order. HomeTheaterFacade(...).watch_movie('Inception') produces the identical 6-call sequence, in the identical order — confirmed by direct comparison of the two call logs, not just by inspection. The Facade doesn't change what happens underneath at all; it changes how much the client has to know and write to make it happen — one call instead of six.
Where This Connects
| This chapter's finding | What it sets up |
|---|---|
A verified real AttributeError, fixed by wrapping rather than rewriting | Chapter 6's Proxy reuses the identical "wrap an object, expose a compatible interface" shape for a genuinely different purpose — controlling access, not fixing incompatibility |
| Facade's verified identical call sequence, just fewer client-facing calls | Software Architecture & System Design's own treatment of layered architecture, where a whole layer often plays exactly this simplifying role |
| Both patterns leaving the wrapped/underlying objects completely unmodified | Chapter 5's Decorator, which also wraps an object without modifying it — but to add behavior, not to translate or simplify it |
Hands-On Exercises
Using this chapter's own PaymentGatewayAdapter as a template, write an adapter for a second legacy gateway whose method is process(total_pence) (British pence, not cents) instead of make_payment. Verify it correctly converts 19.99 dollars into the right number of pence and successfully passes through the same unmodified checkout() function.
Using this chapter's own HomeTheaterFacade, add a end_movie() method that turns everything off in the reverse order it was turned on (DVD player first, then projector, then amplifier). Verify the resulting call log matches the expected reversed order.
Using this chapter's own two verified demonstrations, explain the specific difference between what Adapter fixes and what Facade fixes — that is, why the payment gateway problem couldn't have been solved with a Facade, and why the home theater problem couldn't have been solved with an Adapter.
📄 View solutionChapter 4 Quick Reference
- Adapter: wraps an incompatible object and exposes the interface a client expects, translating each call — verified fixing a real
AttributeErrorand a correct dollars-to-cents conversion (49.99 → 4999) - Facade: hides a complex, multi-step subsystem behind one simple method — verified producing the identical 6-call sequence as manual orchestration, just collapsed into one client-facing call
- Neither pattern modifies the objects it wraps — both add a layer in front, not a change underneath
- Next chapter: Structural Patterns II — Decorator and Composite