Structural Design Patterns

Author: Htunn Thu Thu

Date: January 4, 2026

Tags: #SoftwareDesign #TypeScript #DesignPatterns #Structural

Introduction

Structural patterns help compose objects and classes into larger structures while keeping these structures flexible and efficient. When building my MCP server and IoT platform, I constantly needed to integrate external APIs, add features to existing code, and simplify complex subsystems.

This guide covers four structural patterns I use regularly:

  • Adapter Pattern - Making incompatible interfaces work together

  • Decorator Pattern - Adding behavior to objects dynamically

  • Facade Pattern - Providing simple interfaces to complex systems

  • Proxy Pattern - Controlling access to objects


Adapter Pattern

Allows incompatible interfaces to work together by wrapping an object with a compatible interface.

The Problem I Had

In my Agentic LLM project, I needed to integrate DuckDuckGo's search API, but its response format didn't match my internal interfaces:

My Solution: Adapter Pattern

I created an adapter to convert between interfaces:

Multiple Adapters Example

Later, I added Google Custom Search without changing existing code:


Decorator Pattern

Adds new functionality to objects dynamically without modifying their structure.

The Problem I Had

In my MCP server, I needed to add logging, timing, and error handling to tools without modifying each tool class:

My Solution: Decorator Pattern

I created decorators for cross-cutting concerns:

TypeScript Decorators

TypeScript also has native decorator syntax (experimental):


Facade Pattern

Provides a simplified interface to a complex subsystem.

The Problem I Had

My IoT platform had complex interactions between MongoDB, LLM service, and data formatting:

My Solution: Facade Pattern

I created a simple facade over the complex subsystem:

Real-World Facade: MCP Server Tools

Here's how I used facade in my MCP server to simplify security scanning:


Proxy Pattern

Provides a surrogate or placeholder for another object to control access to it.

The Problem I Had

In my IoT platform, sensor data queries to the LLM were expensive and slow:

My Solution: Caching Proxy

I created a proxy to cache expensive operations:

Virtual Proxy (Lazy Loading)

I also use proxies for lazy initialization of expensive resources:

Protection Proxy (Access Control)

In my MCP server, I use proxies to control access to sensitive operations:


Combining Structural Patterns

Here's a real example combining multiple structural patterns from my MCP server:


When to Use Each Pattern

Adapter Pattern

βœ… Use when:

  • Integrating third-party libraries with incompatible interfaces

  • Working with legacy code

  • Need to switch between alternative implementations

❌ Avoid when:

  • You control both interfaces (just make them compatible)

  • Conversion adds no value

Decorator Pattern

βœ… Use when:

  • Adding responsibilities to objects dynamically

  • Need composable enhancements (logging, caching, timing)

  • Want to avoid subclass explosion

❌ Avoid when:

  • Simple inheritance is sufficient

  • Behavior should be fixed at compile time

Facade Pattern

βœ… Use when:

  • Subsystem is complex with many interdependent classes

  • Want to provide simple interface to complex functionality

  • Need to decouple clients from subsystem implementation

❌ Avoid when:

  • System is already simple

  • Clients need fine-grained control

Proxy Pattern

βœ… Use when:

  • Need lazy initialization of expensive objects

  • Want to add access control, caching, or logging

  • Objects are remote or need controlled access

❌ Avoid when:

  • Direct access is simpler and sufficient

  • Indirection adds unnecessary complexity


Conclusion

Structural patterns help organize code effectively:

  • Adapter: Bridges incompatible interfaces

  • Decorator: Adds behavior flexibly

  • Facade: Simplifies complex systems

  • Proxy: Controls object access

I use these patterns constantly in my TypeScript projects to integrate APIs, add features cleanly, and manage complexity.

What's Next?

References


Previous: ← Creational Patterns | Next: Behavioral Patterns β†’

Last updated