Structural Patterns
Patterns for composing classes and objects into larger structures: Adapter, Decorator, Proxy, Facade, Composite, Bridge and Flyweight. They mostly answer how two things that were not designed for each other can work together.
part ofSoftware design & architectureoverview, primer and where to startread it →on this pageshowhide
explore
questions
page 2 of 2What signals tell you a facade has stopped helping and become a liability, and what would you do about each?
basics
~20 sWarning signs: it mirrors the subsystem method-for-method, it keeps growing into a god-object, it leaks internal types in its signatures, or nobody uses it because callers still import internals. Fix by resizing, splitting, or deleting it.
How should the flyweight factory be implemented — the cache/interning strategy behind the Flyweight pattern — and what concurrency and lifetime issues does it introduce?
basics
~20 sThe factory keeps a map from the shared-state key to the single instance, creating one only on a miss. It must be thread-safe, must not let two callers get two different instances for the same key, and must have a bounding or eviction policy so the map does not grow forever.
How do you decide whether applying the Flyweight pattern will actually pay off, and when should you reject it?
basics
~20 sIt pays off when you have very many objects but few distinct values, the duplicated part is big enough to matter, and the objects are long-lived. Reject it when values are mostly unique, the objects are few or short-lived, or the API damage outweighs the memory saved.
Frameworks generate proxies at runtime to add transactions, security, or caching. How does that generation work, and what are its documented limitations?
basics
~20 sThe framework returns a generated stand-in instead of your object: either a class implementing your interfaces, or a subclass of your class, that runs extra logic then delegates. Limitations: only calls that go through the returned reference are intercepted, so internal self-calls, final/private/static methods, and direct field access are not.
Compare a protection proxy and a remote proxy: what does each control, and what specific hazards does each introduce?
basics
~20 sA protection proxy controls who may call — it checks the caller's rights and forwards or denies. A remote proxy controls where the object is — it hides that the real object lives in another process or machine. The first can be bypassed if callers reach the subject directly; the second hides latency and partial failure.
The Bridge pattern is defined as 'decouple an abstraction from its implementation so that the two can vary independently.' What concrete problem does that solve, and how is Bridge different from Adapter and from Strategy?
basics
~20 sBridge splits one concept into two hierarchies — what it does and how it is done — connected by composition, so you can extend either side without multiplying classes. Adapter reconciles two interfaces that already exist and clash; Bridge is designed up front. Strategy swaps one algorithm, not a whole implementation hierarchy.
How is the Facade pattern used as an architectural boundary — for module public APIs, service SDKs, or a backend-for-frontend — and what changes about the trade-offs at that scale?
basics
~10 sAt architecture scale, a facade becomes a module's or service's single published entry point. Everything behind it can change freely; everything the facade exposes becomes a contract you must version, deprecate and support.
At architecture scale, where do Facade, Proxy, Adapter and Decorator reappear as system-level building blocks, and what do you weigh before adding another layer of indirection?
basics
~20 sThe same intents scale up: an API gateway or service facade simplifies a subsystem, RPC client stubs and sidecars are proxies, anti-corruption layers are adapters, and middleware chains are decorators. Each layer buys decoupling but costs latency, one more hop to debug, and a contract someone must own.
Must a facade be a single class, be stateless, or be a singleton — and how does introducing one affect testing of client code?
basics
~20 sNone of those are required. A facade can be several classes, hold state, and be created per use. For tests, clients now stub one facade instead of many collaborators, which makes their tests shorter — but the facade itself still needs integration tests.
What are the main costs and failure modes of the Bridge pattern, and how do you tell when you have applied it badly?
basics
~20 sBridge adds indirection and a second hierarchy to navigate, and forces you to design the interface between them early. It goes wrong when the interface mirrors the abstraction, leaks implementation details, or exists with only one implementation.
Explain the Flyweight pattern's split between intrinsic and extrinsic state, and describe when the pattern actually pays for itself.
basics
~20 sFlyweight saves memory by sharing one object across many logical occurrences. The shared part (intrinsic state) is context-independent and immutable, such as a character's glyph shape; the varying part (extrinsic state) such as position or colour is passed in by the caller instead of stored per instance.
Scaled up to whole-system boundaries, the Adapter pattern reappears as hexagonal architecture's "ports and adapters" and DDD's anti-corruption layer. What changes at that scale, and how do you decide how many adapters and how thick to make them?
basics
~20 sAt system scale the target interface becomes a "port" your domain owns, and each external system gets an adapter that translates its model into yours. This keeps vendor concepts out of the core, at the cost of extra layers and mapping code.
Where does Bridge-style thinking show up above the class level — in module, plugin and system architecture — and what makes those seams succeed or fail?
basics
~20 sThe same idea scales up: a stable interface between a domain core and swappable technical mechanisms — ports and adapters, driver/plugin interfaces, storage or messaging abstractions. It succeeds when the seam is narrow, primitive and rarely changed.
When is the Composite pattern the wrong choice, and what are the failure modes of an object tree at scale — persistence, depth, and heterogeneous leaves?
basics
~20 sComposite fits only genuine part-whole hierarchies where nodes really share behaviour. It goes wrong when leaves differ too much to share a meaningful interface, when the tree is loaded lazily from a database (one query per node), or when depth comes from untrusted input and overflows the stack.
When would you deliberately NOT use hand-written Decorator wrappers for cross-cutting behavior, and what would you use instead?
basics
~20 sSkip decorators when the behavior applies uniformly to many types (use a middleware pipeline or framework interceptors), when there is only one fixed variation (put it in the class), or when the interface is too large or not designed for wrapping.
What hazards arise from the shared, interned instances that the Flyweight pattern creates — around identity comparison, mutability, locking, serialization and multi-tenancy?
basics
~20 sBecause one object is shared everywhere, any mutation of it affects every user; comparing by reference works until an instance is created outside the factory or evicted; locking on a shared instance can make unrelated code contend or deadlock; and copies from serialization or other tenants silently break the "one instance" assumption.
Beyond a single class, where does the Proxy pattern show up at the architecture level, and when is adding a proxy the wrong call?
basics
~20 sThe same idea scales up: API gateways, reverse proxies, service-mesh sidecars, caching layers, and database connection proxies all stand in front of something and control access to it. It's the wrong call when it adds a hop and an operating cost without policy — pure pass-through indirection.
showing 31–47 of 47