Module 3 / Structural patterns
Module 3 · Core Patterns

Structural patterns

Compose classes and objects into larger structures while keeping those structures flexible and efficient.

0/4 lessons

Adapter

Learn

The Adapter converts the interface of an existing class into another interface that a client expects. It lets classes work together that couldn't otherwise because of incompatible interfaces — without modifying either.

Real-world analogy: a power adapter. Your laptop expects USB-C; the wall outlet provides AC. The adapter bridges the gap. In code, you wrap the adaptee in a class that implements the target interface and translates calls.

// Target interface the client expects interface PaymentProcessor { charge(amount: number): void; } // Adaptee — incompatible third-party API class StripeApi { createCharge(cents: number, currency: string) { … } } // Adapter — translates between the two class StripeAdapter implements PaymentProcessor { constructor(private stripe: StripeApi) {} charge(amount: number) { this.stripe.createCharge(amount * 100, 'usd'); } }
Adapters are one of the most commonly used patterns in practice — anytime you integrate a third-party library behind your own interface, you're writing an adapter.
Practice
Loading…
Recall0/1
Recall

When should you reach for the Adapter pattern?

Decorator

Learn

The Decorator wraps an object to add new behavior at runtime, transparently. Unlike inheritance (which is static and affects all instances), decorators compose dynamically — you can stack them in any combination.

The key constraint: the decorator implements the same interface as the component it wraps. Clients can't tell whether they're talking to the original or a decorated version. This enables open-ended extension without modifying existing classes.

interface DataSource { read(): string; write(data: string): void; } class FileSource implements DataSource { … } // Each decorator wraps a DataSource and adds behavior class EncryptionDecorator implements DataSource { constructor(private source: DataSource) {} read() { return decrypt(this.source.read()); } write(d){ this.source.write(encrypt(d)); } } // Stackable: encrypt + compress new EncryptionDecorator(new CompressionDecorator(new FileSource()))
Decorators can create many small wrapper objects. If you find yourself stacking five decorators deep, consider whether the responsibilities should be restructured instead.
Practice
Loading…
Recall0/1
Recall

What advantage does Decorator have over subclassing for adding behavior?

Composite

Learn

The Composite lets you treat individual objects and groups of objects uniformly. Both leaf nodes and composite (container) nodes implement the same interface, so client code doesn't need to distinguish between them.

Classic examples: file systems (files and directories), UI component trees (buttons and panels), organizational charts (employees and departments). Any tree-like structure where operations apply recursively benefits from Composite.

interface Component { getSize(): number; render(): void; } class File implements Component { getSize() { return this.bytes; } } class Folder implements Component { private children: Component[] = []; getSize() { return this.children.reduce((s, c) => s + c.getSize(), 0); } }
The power of Composite is uniformity: client code calls getSize() or render() without checking whether it's dealing with a leaf or a container. The recursion happens inside the composite.
Practice
Loading…
Recall0/1
Recall

What is the defining characteristic of the Composite pattern?

Facade

Learn

The Facade provides a unified, simplified interface to a complex subsystem. It doesn't replace the subsystem's classes — it sits in front of them, coordinating calls and hiding internal complexity from clients.

Unlike Adapter (which changes an interface to match what a client expects), Facade creates a new, simpler interface on top of existing complexity. The subsystem remains fully accessible for advanced use cases.

Without Facade

Client knowledge
Must know all subsystem classes
Coupling
Tightly coupled to internals
Change impact
Subsystem changes ripple to clients

With Facade

Client knowledge
Knows only the facade
Coupling
Loosely coupled via stable interface
Change impact
Facade absorbs subsystem changes
A facade that grows too large becomes a God Object. Keep it focused on one cohesive workflow; split into multiple facades if needed.
Practice
Loading…
Recall0/1
Recall

How does Facade differ from Adapter?