Deep Dive
low level designdesign patternsoop

Structural Patterns: Composing Objects Into Bigger Things

The seven structural patterns aren't seven clever tricks — they're seven answers to one question: how do you compose classes and objects into larger structures without the composition itself going rigid? A map, and how to tell the confusing ones apart.

·8 min read
Medium

Creational patterns worry about how an object is born. Structural patterns worry about what happens next — how you wire that object together with others into something bigger without the wiring itself becoming the thing you’re afraid to touch.

The failure mode is quiet. A class reaches directly into a third-party type whose interface doesn’t quite match. A feature gets bolted on with a boolean flag, then another, until the combinations explode. A caller is dragged through five collaborators to accomplish one thing. Each is a different way that composition — not creation, not behavior — has calcified.

The smell they all push back on

Here is one ordinary export method. Nothing is broken — it compiles, it ships. But look at how many composition decisions it has nailed down inline, where no caller and no test can reach them.

Composition welded into one method
java

Three separate kinds of rigidity hide in that method: a mismatched interface adapted by hand, cross-cutting concerns wired with flags, and a subsystem with no front door. Each is a different question — and each has its own structural pattern as the answer.

The map

The Gang of Four grouped these seven together because they all answer how do objects fit together, not how do objects get made (creational) or how do objects collaborate over time (behavioral). Read the family as one decision each moves out of your way.

How do objects composeinto a larger structure?Wrap one objectchange how it looks / behavesFront a subsystemsimplify or control accessStructure many objectstrees, axes, shared stateAdaptermatch a mismatched interfaceDecoratoradd responsibilities, stackablyFacadeone simple front doorProxystand-in that guards accessCompositetree treated as oneBridge / Flyweightsplit axes · share memory
The seven structural patterns, organized by what they act on — a single object's interface, a subsystem, or a whole graph of objects. Each moves one composition decision out of the code that uses the structure.

The seven, at a glance

Each governs one composition decision. Reaching for the wrong one is almost always a sign you’ve misread which decision is actually varying.

  • Adapter → — Make an incompatible interface usable without touching either side. Kills the hand-written glue smeared through your code every time a third-party type doesn’t fit. It moves interface matching out of the caller.
  • Decorator → — Add responsibilities to one object at runtime, stackably. Kills the subclass explosion (GzippedEncryptedWatermarkedExporter) and the flag-per-feature branch pile. It moves layered behavior out of the class.
  • Facade → — Put one simple front door over a complicated subsystem. Kills the caller that has to know the order-of-operations across five collaborators. It moves subsystem orchestration out of the client.
  • Proxy → — A stand-in that controls access to the real object — lazy, remote, or protected. Kills the eager load, the leaked network call, the unchecked access sprinkled at every call site. It moves access control out of the caller.
  • Composite → — Treat a tree of objects and a single object uniformly. Kills the if (isLeaf) … else recurse that infects every operation over a hierarchy. It moves the leaf-vs-branch distinction out of the client.
  • Bridge → — Split an abstraction from its implementation so both vary independently. Kills the combinatorial class blowup when two dimensions (shape × renderer, message × transport) each grow on their own. It moves one axis of variation out of the other.
  • Flyweight → — Share immutable intrinsic state across many objects to slash memory. Kills the million near-identical objects that each re-store the same glyph, tile, or particle type. It moves shared state out of the individual instance.

The confusions that cost interviews

Structural patterns look alike on a class diagram — most of them are “an object that holds another object and forwards to it.” The difference is entirely in intent.

Decorator vs Proxy. Both wrap an object of the same interface and delegate to it. The difference is why. A Decorator adds new responsibility the wrapped object didn’t have — compression, a border, a watermark — and you deliberately stack several. A Proxy controls access to an object whose behavior it doesn’t change — it delays creation, checks a permission, or hops the network — and the client ideally never knows it’s there. Decorator enriches; Proxy governs.

Adapter vs Facade vs Bridge. All three sit between a client and something else, so they blur together. But: Adapter changes an interface you don’t own to one you need — it’s reactive glue over an existing, mismatched type. Facade invents a new, simpler interface over a subsystem you do own, hiding its complexity — the subsystem’s real interfaces still exist underneath. Bridge is designed in up front: you deliberately split an abstraction from its implementation so the two can vary on separate axes. Adapter is retrofit, Facade is simplification, Bridge is foresight.

Check yourself

References

Books

  • Gamma, Helm, Johnson, Vlissides — Design Patterns: Elements of Reusable Object-Oriented Software, the Structural Patterns chapter.
  • Joshua Bloch — Effective Java (3rd ed.), Item 18 (“Favor composition over inheritance”) — the principle the whole family rests on.
  • Martin Fowler — Refactoring: Improving the Design of Existing Code, on replacing rigid, hand-wired collaboration with substitutable structure.
Go Premium

Enjoyed this post?

Unlock every deep-dive on system design & distributed systems, and keep your reading streak alive.

View plans

Related Articles