Structural patterns organize relationships between objects. Adapter wraps incompatible interfaces, Decorator adds behavior, and Facade simplifies complex subsystems.
Structural patterns organize relationships between objects. Adapter wraps incompatible interfaces, Decorator adds behavior, and Facade simplifies complex subsystems.
Structural Patterns is one of the most important topics in Design Patterns in 5 Days. This lesson builds the foundation you need before moving to more advanced concepts — take time with each example and run the code yourself.
// Adapter — make incompatible interfaces work together
// Old payment interface
class OldPayPal { makePayment(amount: number, currency: string) { console.log(\`PayPal: \${amount} \${currency}\`); }
}
// New interface your app expects
interface PaymentProcessor { charge(cents: number): void;
}
// Adapter bridges the gap
class PayPalAdapter implements PaymentProcessor { constructor(private paypal: OldPayPal) {} charge(cents: number) { this.paypal.makePayment(cents / 100, 'USD'); }
}
const processor: PaymentProcessor = new PayPalAdapter(new OldPayPal());
processor.charge(4999); // PayPal: 49.99 USD // Decorator — add behavior without subclassing
interface Logger { log(message: string): void;
}
class ConsoleLogger implements Logger { log(message: string) { console.log(message); }
}
class TimestampLogger implements Logger { constructor(private wrapped: Logger) {} log(message: string) { this.wrapped.log(\`[\${new Date().toISOString()}] \${message}\`); }
}
class PrefixLogger implements Logger { constructor(private wrapped: Logger, private prefix: string) {} log(message: string) { this.wrapped.log(\`\${this.prefix} \${message}\`); }
}
// Stack decorators
const logger = new PrefixLogger( new TimestampLogger(new ConsoleLogger()), '[INFO]');
logger.log('Server started');
// [INFO] [2026-04-10T...] Server started // Facade — simplify a complex subsystem
class OrderFacade { constructor( private inventory: InventoryService, private payment: PaymentService, private shipping: ShippingService, private email: EmailService, ) {} async placeOrder(cart: Cart, card: CreditCard, address: Address) { await this.inventory.reserve(cart.items); await this.payment.charge(card, cart.total); const tracking = await this.shipping.dispatch(cart.items, address); await this.email.sendConfirmation(cart.userId, tracking); return tracking; }
} Before moving on, make sure you can answer these without looking: