Skip to main content

Adapter Pattern

Make incompatible interfaces work together through translation

Pattern Overview

🔗 The Adapter Pattern - Interface Compatibility

Allows incompatible interfaces to work together by providing a wrapper that translates one interface to another. Perfect for integration!

  • Core Problem Solved:
  • Integrate incompatible interfaces without modifying existing code
  • Wrap third-party libraries with consistent APIs
  • Bridge legacy systems with modern applications
  • Enable code reuse across different interface requirements
🔍 Three Implementation Approaches:
  • Object Adapter: Composition-based adapter using existing objects
  • Class Adapter: Inheritance-based adapter (less common in JS/TS)
  • Function Adapter: Simple function-based interface translation
  • Real-World Applications:
  • API wrappers and gateway adapters
  • Database ORM adapters for different databases
  • Payment gateway integration layers
  • Legacy code integration with modern systems
  • Third-party library wrapper implementations
  • File system adapters across platforms
  • Modern Usage Examples:
  • React component wrappers for different UI libraries
  • GraphQL adapters for REST APIs
  • Node.js stream adapters
  • Cloud provider SDK adapters

Examples:
Legacy printer integration
Input:
new PrinterAdapter(legacyPrinter).print('Hello World')
Output:
LEGACY PRINT: HELLO WORLD (with job counting)
Weather API adaptation
Input:
weatherAdapter.getWeatherData()
Output:
{ temperature: 75, description: 'sunny', humidity: 60, timestamp: Date }
Payment gateway unification
Input:
stripeAdapter.processPayment(10.00, 'USD')
Output:
{ success: true, transactionId: 'stripe_abc123' }

Concepts

interface translationwrapper patterncompatibility layer

Complexity Analysis

Time:O(1)
Space:O(1)

Implementation

object-adapter

Time: O(1) | Space: O(1)
// Target interface our application expects
interface ModernPrinter {
  print(document: string): void;
  isReady(): boolean;
  getJobCount(): number;
}

// Legacy class we need to adapt
class LegacyPrinter {
  public printOldWay(text: string): void {
    console.log(`LEGACY PRINT: ${text.toUpperCase()}`);
  }

  public getStatus(): string {
    return "READY_TO_PRINT";
  }
}

// Adapter that makes legacy printer work with modern interface
class PrinterAdapter implements ModernPrinter {
  private jobCount: number = 0;

  constructor(private legacyPrinter: LegacyPrinter) {}

  public print(document: string): void {
    // Translate modern call to legacy method
    this.legacyPrinter.printOldWay(document);
    this.jobCount++;
  }

  public isReady(): boolean {
    // Translate legacy status to boolean
    return this.legacyPrinter.getStatus() === "READY_TO_PRINT";
  }

  public getJobCount(): number {
    return this.jobCount;
  }
}

// Usage
const legacyPrinter = new LegacyPrinter();
const adapter = new PrinterAdapter(legacyPrinter);

adapter.print("Hello World"); // Works with modern interface
console.log(adapter.isReady()); // true
console.log(adapter.getJobCount()); // 1