Entwurfsmuster in JavaScript mit Codebeispielen

Online Python-Trainer für Anfänger

Lernen Sie Python einfach ohne theoretische Überlastung. Lösen Sie praktische Aufgaben mit automatischer Überprüfung und schreiben Sie Code direkt im Browser.

Kurs starten

Entwurfsmuster in JavaScript mit Beispielen



Entwurfsmuster (design patterns) sind bewährte Lösungen für typische Aufgaben in der Softwareentwicklung. Für JavaScript-Entwickler ist die Kenntnis von Mustern besonders wichtig, da die Sprache ein flexibles Objektmodell besitzt und sowohl auf dem Client als auch auf dem Server (Node.js) weit verbreitet ist. In diesem Artikel werden wir vier Schlüsselmuster mit praktischen Beispielen in JavaScript behandeln.



Warum sollte man Entwurfsmuster lernen?

Muster helfen dabei:

  • Die Wartung und Skalierung von Code zu vereinfachen
  • Code lesbarer und vorhersehbarer zu machen
  • Das "Rad neu zu erfinden" zu vermeiden
  • Die Kommunikation im Team zu verbessern (gemeinsame Sprache)


1. Singleton (Einzelstück)

Das Singleton-Muster stellt sicher, dass eine Klasse nur eine einzige Instanz hat, und bietet einen globalen Zugriffspunkt darauf. In Node.js wird dieses Muster häufig für Datenbankverbindungen, Konfigurationsverwaltung oder Logging verwendet.



class DatabaseConnection {  constructor() {    if (DatabaseConnection.instance) {      return DatabaseConnection.instance;    }    this.connection = null;    DatabaseConnection.instance = this;  }

connect() { // Simulation der DB-Verbindung this.connection = "connected"; console.log("Datenbankverbindung hergestellt"); }

query(sql) { if (!this.connection) { throw new Error("Keine Datenbankverbindung"); } console.log(`Ausführen der Abfrage: ${sql}`); return { data: [] }; }}

// Verwendungconst db1 = new DatabaseConnection();const db2 = new DatabaseConnection();

db1.connect();console.log(db1 === db2); // true - beide verweisen auf dieselbe Instanzdb2.query("SELECT * FROM users");


Wann anwenden: Verwaltung gemeinsamer Ressourcen (DB, Konfiguration, Cache). Vorsicht: Übermäßige Verwendung kann zu starker Kopplung des Codes führen.



2. Factory (Fabrik)

Die Factory Method definiert eine Schnittstelle zur Erstellung eines Objekts, ermöglicht es Unterklassen jedoch, den Typ des erstellten Objekts zu ändern. In JavaScript wird dies oft durch normale Funktionen oder Klassen implementiert.



class User {  constructor(name, role) {    this.name = name;    this.role = role;  }

getPermissions() { return []; }}

class Admin extends User { getPermissions() { return ["read", "write", "delete", "manage"]; }}

class Editor extends User { getPermissions() { return ["read", "write"]; }}

class Viewer extends User { getPermissions() { return ["read"]; }}

// Fabrikclass UserFactory { createUser(name, role) { switch (role) { case "admin": return new Admin(name, role); case "editor": return new Editor(name, role); case "viewer": return new Viewer(name, role); default: throw new Error("Unbekannte Rolle"); } }}

// Verwendungconst factory = new UserFactory();const admin = factory.createUser("Anna", "admin");const viewer = factory.createUser("Ivan", "viewer");

console.log(admin.getPermissions()); // ["read", "write", "delete", "manage"]console.log(viewer.getPermissions()); // ["read"]


Vorteile: Zentrale Verwaltung der Objekterstellung, einfaches Hinzufügen neuer Typen, Kapselung der Instanziierungslogik.



3. Observer (Beobachter)

Das Observer-Muster definiert eine "Eins-zu-Viele"-Abhängigkeit zwischen Objekten. Wenn ein Objekt (Subjekt) seinen Zustand ändert, werden alle abhängigen Objekte (Beobachter) automatisch benachrichtigt. Dies ist die Grundlage der ereignisgesteuerten Programmierung in Node.js.



class EventEmitter {  constructor() {    this.events = {};  }

on(eventName, listener) { if (!this.events[eventName]) { this.events[eventName] = []; } this.events[eventName].push(listener); }

emit(eventName, ...args) { const listeners = this.events[eventName]; if (listeners) { listeners.forEach(listener => listener(...args)); } }

off(eventName, listener) { const listeners = this.events[eventName]; if (listeners) { this.events[eventName] = listeners.filter(l => l !== listener); } }}

// Verwendungconst emitter = new EventEmitter();

function onUserLoggedIn(user) { console.log(`Benutzer eingeloggt: ${user}`);}

emitter.on("userLoggedIn", onUserLoggedIn);emitter.emit("userLoggedIn", "Anna");emitter.off("userLoggedIn", onUserLoggedIn);


Wann anwenden: Ereignisbehandlung, Benachrichtigungssysteme, Aktualisierung der Benutzeroberfläche. Vorteile: Entkopplung von Komponenten, Flexibilität und Erweiterbarkeit.

Blogs

Buchempfehlungen