Adapter

The Adapter pattern lets classes with incompatible interfaces work together by wrapping one of them with a translation layer.

Intent

You have an existing class whose interface doesn’t match what your client code expects. Rather than rewriting the class, you wrap it in an adapter that translates calls between the two interfaces.

Structure

  • Target — the interface the client expects.
  • Adaptee — the existing class with an incompatible interface.
  • Adapter — implements Target and delegates to the Adaptee.

Example

class LegacyPrinter {
  printOldWay(text: string) {
    console.log(`*** ${text} ***`);
  }
}

interface Printer {
  print(text: string): void;
}

class PrinterAdapter implements Printer {
  constructor(private legacy: LegacyPrinter) {}

  print(text: string) {
    this.legacy.printOldWay(text);
  }
}

const printer: Printer = new PrinterAdapter(new LegacyPrinter());
printer.print("Hello");

When to Use It

  • You want to use an existing class but its interface doesn’t match what you need.
  • You want to create a reusable class that works with unrelated classes that don’t share a common interface.

Object vs Class Adapter

  • Object adapter — uses composition (shown above). More flexible.
  • Class adapter — uses multiple inheritance. Not available in all languages.