CMD Guide
HomeOO & Low-Level DesignDesign Patterns Overview

Structural Patterns — Introduction

Structural patterns compose objects into larger structures while keeping those structures flexible. They answer: how do I wrap, adapt, or simplify collaboration without rewriting the parts I do not own?

Structural patterns in one example

Structural patterns wrap or compose objects so the client sees the shape it expects. Suppose your application defines a PaymentGateway interface with charge(long cents), but you already own a legacy LegacyPayPal class that exposes sendPayment(double dollars). You cannot change the legacy class, and you do not want the rest of the application to know about it. An Adapter solves this by implementing the expected interface and translating each call.

// The interface the application expects
interface PaymentGateway {
    Receipt charge(long cents);
}

// The legacy class you cannot change
class LegacyPayPal {
    void sendPayment(double dollars) { /* ... */ }
}

// Adapter: implements the expected interface, delegates to the legacy object
class PayPalAdapter implements PaymentGateway {
    private final LegacyPayPal legacy = new LegacyPayPal();

    public Receipt charge(long cents) {
        legacy.sendPayment(cents / 100.0);
        return new Receipt();
    }
}

Now suppose you want to log every charge without changing either the adapter or the real gateway. A Decorator wraps any PaymentGateway, adds logging, and forwards the call with the same interface.

class LoggingGateway implements PaymentGateway {
    private final PaymentGateway delegate;

    LoggingGateway(PaymentGateway delegate) { this.delegate = delegate; }

    public Receipt charge(long cents) {
        System.out.println("charging " + cents + " cents");
        return delegate.charge(cents); // always forwards
    }
}

The intent is what separates them: Adapter changes the interface so an existing object can be used; Decorator keeps the same interface and adds behavior while always forwarding.

Why patterns matter

Design patterns are not libraries or syntax rules. They are shared names for recurring solutions so teams can discuss design without redrawing the same diagram. The value is not the pattern itself; it is the ability to say "this is an Adapter" and have everyone understand the forces, structure, and consequences.

In structural design, patterns matter because systems are rarely built from scratch. You inherit legacy classes, third-party SDKs, and frameworks whose interfaces do not match your model. Structural patterns give you disciplined ways to bridge those gaps without modifying code you do not own.

How to read a pattern

Every pattern description should answer three questions in order:

  1. Problem. What design force makes simple code fail? (Example: an existing class has the wrong interface.)
  2. Structure. What classes collaborate and what are their responsibilities? (Example: Adapter implements the target interface and delegates to the adaptee.)
  3. Consequences. What do you gain and what do you pay? (Example: reuse without modification, but an extra layer of indirection.)

If a pattern description skips any of the three, you do not have enough to apply it correctly.

Pattern-selection flowchart

Do you need to use an existing class with a different interface?
        | yes
        v
   Use Adapter
        | no
        v
Do you need to add behavior without subclassing?
        | yes
        v
   Use Decorator
        | no
        v
Do you need a simpler entry point to a complex subsystem?
        | yes
        v
   Use Facade
        | no
        v
Do many objects share most of their state?
        | yes
        v
   Use Flyweight
        | no
        v
Do you need controlled or remote access to an object?
        | yes
        v
   Use Proxy
        | no
        v
   Keep plain composition

Types of Structural Design Patterns

When it comes to types of structural design patterns, there are many types, but some of the common ones that developers frequently use are:

When structural wrapping is overkill

Every wrapper is another class to read, test, and debug, and a deep decorator chain can obscure where the real work happens. Reach for an Adapter only when an existing interface genuinely does not fit; reach for a Decorator only when behavior must be added without subclassing or at runtime. For a one-off need — such as logging a single method call — a small helper or plain composition is usually clearer than a full structural pattern. Named patterns earn their keep when the same wrapping concern repeats across the codebase.

Self-check (structural)

  1. Adapter vs Decorator intent. Adapter changes the interface so an existing object can be used; Decorator keeps the same interface and adds behavior while always forwarding. Same structure (wrapper), different force. Which would you use to integrate a third-party SDK that speaks dollars while your app speaks cents?
  2. When Bridge with N=1 fails. Bridge pays for independent variation of abstraction and implementation. If you will never have a second implementation (or a second abstraction), Bridge is premature hierarchy — a single concrete class is clearer.
  3. Proxy may skip forward. Unlike Decorator, a Proxy is allowed to short-circuit (cache hit, access denied, lazy not-yet-loaded). If the wrapper always forwards and only adds behavior, say Decorator; if it may refuse or substitute, say Proxy.
  4. Facade is optional. A Facade is a usual-path front door; subsystem classes remain public for fine-grained use. If clients cannot bypass the facade, you may have built a god object or the wrong boundary. When would you still call subsystem classes directly?
Common Structural Patterns
Common Structural Patterns

Stacking decorators — order is not free

Because decorators share the target interface, they compose: new LoggingGateway(new MetricsGateway(new PayPalAdapter(...))). The wrap order is a design decision, not a formality — metrics-outside-logging counts every attempt including ones logging might short-circuit, while logging-outside-metrics changes what the counters see. Two rules keep a chain honest: a decorator must always forward and must not change the method's meaning (a decorator that alters the result breaks the client's Liskov assumption and is really a different operation). And why decorate at all rather than subclass for the logging case? Subclassing freezes you to one parent and multiplies classes — LoggingPayPal, LoggingStripe, LoggingAdyen — whereas one LoggingGateway wraps any PaymentGateway.

Operability signal (what wrapping breaks in production)

Wrappers fail quietly. A decorator stack applied twice in DI config causes a double-charge; a unit mismatch at an adapter boundary (cents vs dollars) silently over- or under-charges by 100×; a decorator that accidentally wraps itself recurses until the stack overflows. Guard with an outlier alert on charge_amount and a reconciliation check — and keep only boundary work (unit conversion) in the adapter, never domain pricing rules.

🤖 Don't fully get this? Learn it with Claude

Stuck on Structural Patterns — Introduction? Open Claude, copy a block below, and it'll teach you this exact concept — visually and interactively.

🎨 Explain it visually

Build the mental picture, not memorization.

I just read a lesson on **Structural Patterns — Introduction** (OO & Low-Level Design) and want to truly understand it. Explain Structural Patterns — Introduction from first principles using ONE vivid real-world analogy and a visual mental model — draw it as ASCII art or a clear step-by-step diagram — with a concrete example using real numbers. Then ask me one question to check I got the mental picture, and wait for my reply. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🤔 Walk me through it (interactive)

Socratic — adapts to where you're stuck.

Teach me **Structural Patterns — Introduction** interactively. Ask me ONE guiding question at a time, wait for my answer, and adapt to my confusion — build the idea with me step by step instead of explaining it all at once. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🧪 Quiz me & fix my gaps

Active recall exposes what you missed.

Quiz me on **Structural Patterns — Introduction** with 5 questions, easy to tricky, ONE at a time. Tell me if each answer is right; at the end, explain clearly what I got wrong and why. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🧠 Make it stick

Intuition + hook + flashcards for long-term memory.

Help me remember **Structural Patterns — Introduction** for the long term: give the one-sentence intuition, a memorable hook/mnemonic, a tiny worked example, and 3 active-recall flashcards (Q -> A). If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.

📝 My notes