Back

Was ist das Dependency Inversion Principle? Einfach erklärt

Was ist das Dependency Inversion Principle? Einfach erklärt

Das Dependency Inversion Principle (DIP) ist eines der fünf SOLID-Prinzipien der objektorientierten Programmierung. Es hilft dabei, flexible, entkoppelte Systeme zu erstellen, indem die Richtung der Abhängigkeit verändert wird – von konkreten Implementierungen hin zu abstrakten Verträgen. Dieser Artikel wird Ihnen helfen, DIP in einfacher Sprache zu verstehen, mit Beispielen, die Sie sofort anwenden können.

Wichtige Erkenntnisse

  • Module höherer Ebene sollten nicht von Modulen niedrigerer Ebene abhängen; beide sollten von Abstraktionen abhängen
  • DIP ermöglicht eine flexible und testbare Architektur
  • Sie werden sehen, wie Sie DIP mit realen Beispielen in mehreren Programmiersprachen anwenden können

Die offizielle Definition

Module höherer Ebene sollten nicht von Modulen niedrigerer Ebene abhängen. Beide sollten von Abstraktionen abhängen. Abstraktionen sollten nicht von Details abhängen. Details sollten von Abstraktionen abhängen.

Lassen Sie uns das aufschlüsseln:

  • Modul höherer Ebene: enthält Geschäftslogik (z.B. eine Bestellung aufgeben)
  • Modul niedrigerer Ebene: erledigt spezifische Aufgaben (z.B. eine E-Mail senden)
  • Abstraktion: eine Schnittstelle oder Basisklasse, die Verhalten definiert, nicht die Implementierung

Eine visuelle Analogie

Stellen Sie sich vor, Sie haben einen OrderService, der eine E-Mail-Benachrichtigung sendet, wenn eine Bestellung aufgegeben wird.

Ohne DIP:

OrderService --> EmailService

OrderService ist eng mit EmailService gekoppelt. Sie können ihn nicht einfach austauschen oder mocken.

Mit DIP:

OrderService --> INotificationService <-- EmailService

Jetzt hängen beide Module von einer Abstraktion (INotificationService) ab.

Ein Codebeispiel: ohne DIP (TypeScript)

class EmailService {
  send(message: string) {
    console.log(`Sending email: ${message}`);
  }
}

class OrderService {
  constructor(private emailService: EmailService) {}

  placeOrder() {
    this.emailService.send("Order placed");
  }
}

Dies koppelt OrderService eng an EmailService.

Refaktorisiert: mit DIP (TypeScript)

interface INotificationService {
  send(message: string): void;
}

class EmailService implements INotificationService {
  send(message: string) {
    console.log(`Sending email: ${message}`);
  }
}

class OrderService {
  constructor(private notifier: INotificationService) {}

  placeOrder() {
    this.notifier.send("Order placed");
  }
}

DIP in Python

from abc import ABC, abstractmethod

class NotificationService(ABC):
    @abstractmethod
    def send(self, message: str):
        pass

class EmailService(NotificationService):
    def send(self, message: str):
        print(f"Sending email: {message}")

class OrderService:
    def __init__(self, notifier: NotificationService):
        self.notifier = notifier

    def place_order(self):
        self.notifier.send("Order placed")

# Usage
service = OrderService(EmailService())
service.place_order()

DIP in Java

interface NotificationService {
    void send(String message);
}

class EmailService implements NotificationService {
    public void send(String message) {
        System.out.println("Sending email: " + message);
    }
}

class OrderService {
    private NotificationService notifier;

    public OrderService(NotificationService notifier) {
        this.notifier = notifier;
    }

    public void placeOrder() {
        notifier.send("Order placed");
    }
}

// Usage
OrderService service = new OrderService(new EmailService());
service.placeOrder();

Warum DIP wichtig ist

  • Testbarkeit: Reale Abhängigkeiten durch Mocks oder Fakes ersetzen
  • Flexibilität: Implementierungen wechseln, ohne die Logik höherer Ebene zu berühren
  • Trennung der Belange: Jedes Modul erledigt eine Aufgabe und kommuniziert über Verträge

Häufiges Missverständnis: DIP ≠ Dependency Injection

Sie sind verwandt, aber nicht dasselbe:

  • DIP geht darum, wer von wem abhängt (Richtung der Abhängigkeit)
  • Dependency Injection ist eine Möglichkeit, DIP anzuwenden — indem Abhängigkeiten injiziert werden, anstatt sie fest zu kodieren

Wann DIP anwenden

Verwenden Sie es, wenn:

  • Sie Geschäftslogik schreiben möchten, die sich nicht um die zugrunde liegende Implementierung kümmert
  • Sie an einer geschichteten oder modularen Anwendung arbeiten
  • Sie für Testbarkeit oder Erweiterbarkeit entwickeln

Fazit

Das Dependency Inversion Principle dreht die übliche Richtung der Abhängigkeit um — sodass Abstraktionen, nicht Implementierungen, Ihre Architektur definieren. Es macht Ihren Code wiederverwendbarer, testbarer und robuster gegenüber Änderungen.

FAQs

Es ist ein Designprinzip, bei dem Module höherer Ebene und Module niedrigerer Ebene beide von Abstraktionen abhängen, anstatt voneinander.

Nein. DIP ist ein Prinzip. Dependency Injection ist eine Technik, um DIP zu erreichen.

Weil Sie reale Abhängigkeiten durch Mocks oder Stubs ersetzen können, die der gleichen Schnittstelle folgen.

Interfaces helfen in TypeScript, aber in JavaScript können Sie Objektformverträge und Muster verwenden, um dasselbe zu erreichen.

Listen to your bugs 🧘, with OpenReplay

See how users use your app and resolve issues fast.
Loved by thousands of developers