December 19, 2025 (3mo ago) — last updated February 10, 2026 (2mo ago)

Adapter-Muster: TypeScript, React & Node.js Beispiele

Erfahren Sie, wie das Adapter-Muster inkompatible Schnittstellen mit TypeScript-, React- und Node.js-Beispielen verbindet, um Integrationen und Legacy-Code zu modernisieren.

← Back to blog
Cover Image for Adapter-Muster: TypeScript, React & Node.js Beispiele

Erfahren Sie, wie das Adapter-Muster inkompatible Schnittstellen mit TypeScript-, React- und Node.js-Beispielen verbindet, um Integrationen und Legacy-Code zu modernisieren.

Adapter-Muster: TypeScript, React & Node.js Beispiele

Zusammenfassung: Erfahren Sie, wie das Adapter-Muster inkompatible Schnittstellen in TypeScript, React und Node.js verbindet – mit praktischen, realen Beispielen.

Einführung

Hatten Sie schon einmal eine eigentlich brauchbare Bibliothek oder ein Legacy-Modul, das einfach nicht mit dem Rest Ihres Systems zusammenpasst? Das ist wie wenn man einen europäischen Adapter in eine nordamerikanische Steckdose stecken will — beides funktioniert, aber die Schnittstellen stimmen nicht überein. Das Adapter-Muster löst das, indem es eine Schnittstelle in eine andere übersetzt, sodass Sie vorhandenen Code wiederverwenden können, ohne ihn zu ändern.

Dieser Leitfaden erklärt das Muster, zeigt TypeScript- und React-Beispiele und demonstriert einen Node.js-Adapter, der callback-basierte Module modernisiert. Der Fokus liegt auf praktischen Techniken, die Sie sofort anwenden können, um Integrationen aufzuräumen und die Testbarkeit zu verbessern.

Warum das Adapter-Muster wichtig ist

Das Adapter-Muster ist ein strukturelles Muster, das ein inkompatibles Objekt umschließt und die Schnittstelle bereitstellt, die Ihr Code erwartet. Es wurde erstmals von der Gang of Four 1994 dokumentiert1. Adapter sind essenziell, um Drittanbieter-APIs zu integrieren, Legacy-Code zu modernisieren und unterschiedliche Datenquellen zu vereinheitlichen.

Typische Szenarien, in denen Adapter helfen:

  • Integration von Drittanbieter-APIs, die unterschiedliche Datenformen zurückgeben.
  • Modernisierung von Legacy-Callback-APIs, damit sie mit async/await funktionieren.
  • Vereinheitlichung mehrerer Datenquellen in eine einzige Schnittstelle für UI-Komponenten.

Durch den Einsatz eines Adapters bleibt die Geschäftslogik sauber und entkoppelt von externen Systemen.

Adapter-Muster im Überblick

KonzeptBeschreibung
TypStrukturell
HauptzweckObjekte mit inkompatiblen Schnittstellen zusammenarbeiten lassen
KernideeDen Adaptee umschließen, um die Ziel-Schnittstelle bereitzustellen
Zentrales Problem, das gelöst wirdVorhandene Klassen wiederverwenden, ohne deren Quellcode zu ändern
Häufige AnwendungsfälleDrittanbieter-Bibliotheken, Legacy-Code, mehrere Datenquellen

Struktur und Rollen

Das Muster hat vier Rollen:

  1. Der Client — der Code, der eine bestimmte Schnittstelle benötigt.
  2. Die Ziel-Schnittstelle — das Vertragswerk, das der Client erwartet.
  3. Der Adaptee — die inkompatible Klasse oder das Modul mit der benötigten Funktionalität.
  4. Der Adapter — implementiert die Ziel-Schnittstelle und delegiert an den Adaptee, wobei Aufrufe bei Bedarf übersetzt werden.

Zwei übliche Adapter-Stile:

  • Objektadapter (Komposition): Der Adapter hält eine Instanz des Adaptee. Dies ist der flexibelste Ansatz.
  • Klassenadapter (Vererbung): Der Adapter erbt vom Adaptee und implementiert die Ziel-Schnittstelle. Das erfordert Mehrfachvererbung und ist in modernem JavaScript und TypeScript weniger gebräuchlich.

Praktisches Beispiel: TypeScript + React

Stellen Sie sich ein Dashboard vor, das Benutzerprofile von zwei Diensten mit unterschiedlichen Antwortformen erhält. Ohne Adapter wären Komponenten voller bedingter Logik.

Inkompatible API-Formen

// Data from UserServiceA
interface UserA {
  userId: number;
  fullName: string;
  emailAddress: string;
}

// Data from UserServiceB
interface UserB {
  id: string;
  name: string;
  contact: {
    email: string;
  };
}

Ziel-Schnittstelle, die unsere App erwartet

interface UnifiedUser {
  id: string;
  name: string;
  email: string;
}

TypeScript-Adapter

// Adapter for UserServiceA
function adaptUserA(userA: UserA): UnifiedUser {
  return {
    id: userA.userId.toString(),
    name: userA.fullName,
    email: userA.emailAddress,
  };
}

// Adapter for UserServiceB
function adaptUserB(userB: UserB): UnifiedUser {
  return {
    id: userB.id,
    name: userB.name,
    email: userB.contact.email,
  };
}

Die Zentralisierung von Transformationen hält Komponenten sauber und widerstandsfähig. Wenn eine API ein Feld umbenennt, ändert sich nur der Adapter.

React-Komponente, die vereinheitlichte Daten konsumiert

interface UserProfileProps {
  user: UnifiedUser;
}

const UserProfile: React.FC<UserProfileProps> = ({ user }) => {
  return (
    <div>
      <h2>{user.name}</h2>
      <p>ID: {user.id}</p>
      <p>Email: {user.email}</p>
    </div>
  );
};

Diese Komponente stützt sich auf eine einzige, vorhersehbare Form, was Tests und Wiederverwendung vereinfacht.

Beispiel: Modernisierung eines callback-basierten Node.js-Moduls

Legacy-Module verwenden oft Error-First-Callbacks. Statt ein stabiles Modul zu ändern, erstellen Sie einen Adapter, der eine Promise-basierte API bereitstellt.

Legacy Adaptee (nicht ändern)

// legacyFileProcessor.js
const fs = require('fs');

class LegacyFileProcessor {
  processFile(filePath, callback) {
    fs.readFile(filePath, 'utf8', (err, data) => {
      if (err) {
        return callback(err, null);
      }
      const processedContent = data.toUpperCase();
      callback(null, processedContent);
    });
  }
}

module.exports = LegacyFileProcessor;

Adapter, der ein Promise zurückgibt

// FileProcessorAdapter.js
const LegacyFileProcessor = require('./legacyFileProcessor');

class FileProcessorAdapter {
  constructor() {
    this.legacyProcessor = new LegacyFileProcessor();
  }

  processFile(filePath) {
    return new Promise((resolve, reject) => {
      this.legacyProcessor.processFile(filePath, (err, data) => {
        if (err) return reject(err);
        resolve(data);
      });
    });
  }
}

module.exports = FileProcessorAdapter;

Dies spiegelt das Verhalten von Node’s util.promisify wider, hält die Adaptationslogik jedoch explizit und testbar3.

Verwendung des Adapters im Anwendungs-Code

const FileProcessorAdapter = require('./FileProcessorAdapter');
const fileProcessor = new FileProcessorAdapter();

async function handleFileProcessing() {
  try {
    console.log('Processing file with modern async/await...');
    const content = await fileProcessor.processFile('my-file.txt');
    console.log('Processed Content:', content);
  } catch (error) {
    console.error('An error occurred:', error);
  }
}

handleFileProcessing();

So bleibt der Legacy-Code unangetastet, während der Rest Ihrer Codebasis eine moderne Schnittstelle erhält.

Wann man einen Adapter verwenden sollte

Verwenden Sie einen Adapter, wenn zwei Komponenten nicht direkt kommunizieren können, weil ihre Schnittstellen unterschiedlich sind. Typische Szenarien:

  • Integration einer Drittanbieter-API, deren Eingaben oder Ausgaben nicht zu Ihren Modellen passen.
  • Umschließen von Legacy-Callback-APIs, damit sie mit async/await funktionieren.
  • Unterstützung mehrerer Datenquellen mit unterschiedlichen Formaten durch Erstellung eines Adapters pro Quelle.

Wann kein Adapter verwendet werden sollte:

  • Wenn Sie beide Systeme kontrollieren und ein kleiner Refactor das Problem löst, bevorzugen Sie direkte Refaktorisierung.
  • Wenn Ihr Ziel darin besteht, ein komplexes Teilsystem zu vereinfachen, ziehen Sie stattdessen ein Facade-Muster in Betracht. Eine Facade bietet einen vereinfachten, hochrangigen Einstiegspunkt; ein Adapter konzentriert sich nur auf Kompatibilität.

Kurze Entscheidungs-Checkliste

SituationAdapter verwenden?Warum
Muss eine Drittanbieter-Bibliothek mit inkompatibler API verwendenJaSie können die Bibliothek nicht ändern, also passen Sie sich ihr an
Beide Seiten kontrollieren und Änderung ist kleinNeinDirekt refactoren, um zusätzliche Indirektion zu vermeiden
Brauche eine vereinfachte hochrangige Schnittstelle zu einem komplexen SystemNeinFacade ist besser geeignet
Legacy-Systeme schrittweise migrierenJaAlte Komponenten umhüllen, um neue Schnittstellen zu erfüllen
Mehrere unterschiedlich strukturierte DatenquellenJaAdapter vereinheitlichen sie in eine Form

Tests und Performance

Adapter verbessern die Testbarkeit, indem sie Kernlogik von externen Systemen entkoppeln. Sie können die Schnittstelle eines Adapters mocken, um Komponenten isoliert zu testen, und Adapter separat testen, um die Übersetzungslogik zu verifizieren.

Der Performance-Overhead durch einen Adapter ist minimal — in der Regel ein zusätzlicher Funktionsaufruf — und gegenüber Netzwerk-I/O oder Datenbankabfragen vernachlässigbar. Für die meisten Webanwendungen überwiegen die Wartbarkeits- und Entkopplungsvorteile die geringe Kosten. JavaScript bleibt laut der Stack Overflow Developer Survey die am meisten genutzte Sprache, was zeigt, wie oft Entwickler vor Integrationsaufgaben stehen, die Adapter lösen4.

Häufig gestellte Fragen

F: Welches Problem löst das Adapter-Muster?

A: Es behebt Schnittstelleninkompatibilitäten, indem es Aufrufe eines Clients in Aufrufe übersetzt, die der Adaptee versteht, sodass Sie Code wiederverwenden können, ohne ihn zu ändern.

F: Wie hilft ein Adapter bei Legacy-Code?

A: Ein Adapter kapselt Legacy-Module und stellt eine moderne Schnittstelle bereit, so dass Sie alten, stabilen Code in neue Anwendungen integrieren können, ohne riskante Überarbeitungen.

F: Wann sollte ich ein Adapter-Muster gegenüber anderen Mustern wählen?

A: Wählen Sie ein Adapter-Muster, wenn Sie Kompatibilität zwischen zwei nicht passenden Schnittstellen benötigen. Wenn Sie ein ganzes Teilsystem vereinfachen möchten, ist eine Facade geeigneter.


At Clean Code Guy, we help teams implement practical design patterns that turn brittle, complex codebases into assets that are resilient, testable, and a pleasure to work on. If you’re wrestling with a legacy system or tricky integrations, our Clean Code Audits can give you a clear, actionable roadmap to a healthier architecture. Learn how we can help you ship better code, faster.

1.
Erich Gamma, Richard Helm, Ralph Johnson und John Vlissides, Design Patterns: Elements of Reusable Object-Oriented Software (Addison-Wesley, 1994). [https://en.wikipedia.org/wiki/Design_Patterns_(book)](https://en.wikipedia.org/wiki/Design_Patterns_(book))
2.
Adapter pattern overview and examples: https://www.geeksforgeeks.org/adapter-pattern/
3.
Node.js documentation for util.promisify, a common approach to convert callbacks to Promises: https://nodejs.org/api/util.html#utilpromisifyoriginal
4.
Stack Overflow Developer Survey 2023, showing the prevalence of JavaScript and web technologies that commonly require integration work: https://survey.stackoverflow.co/2023/
← Back to blog
🙋🏻‍♂️

KI schreibt Code.
Sie lassen ihn bestehen.

Im Zeitalter der KI-Beschleunigung ist Clean Code nicht nur gute Praxis — es ist der Unterschied zwischen Systemen, die skalieren, und Codebasen, die unter ihrem eigenen Gewicht zusammenbrechen.