Dependency Injection in Go: für Anfänger – Beispiele und Prinzipien

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

Dependency Injection in Go: für Anfänger



Dependency Injection (DI), oder Abhängigkeitsinjektion, ist eines der wichtigsten Entwurfsmuster, das hilft, sauberen, testbaren und wartbaren Code zu schreiben. In der Welt von Go, wo Einfachheit und Klarheit am höchsten geschätzt werden, ermöglicht DI die Vermeidung von „gottgleichen Objekten“ und starren Kopplungen zwischen Komponenten. In diesem Artikel werden wir untersuchen, was Dependency Injection in Go ist, warum sie benötigt wird und wie man sie in der Praxis mit einfachen und verständlichen Beispielen anwendet.



Was ist Dependency Injection?



Stellen Sie sich vor, Sie schreiben ein Programm, das Willkommens-E-Mails an Benutzer sendet. Ihr Code würde wahrscheinlich so aussehen:



package main

import "fmt"

type EmailService struct{}

func (e *EmailService) SendWelcomeEmail(userEmail string) { fmt.Printf("Sende E-Mail an %s", userEmail)}

type UserController struct { emailService *EmailService}

func NewUserController() *UserController { return &UserController{ emailService: &EmailService{}, // Starre Kopplung }}

func (uc *UserController) RegisterUser(email string) { // ... Registrierungslogik uc.emailService.SendWelcomeEmail(email)}

func main() { controller := NewUserController() controller.RegisterUser("user@example.com")}


Das Problem an diesem Code ist, dass UserController selbst eine Instanz von EmailService erstellt. Dies nennt man starre Kopplung. Wenn Sie EmailService durch z. B. SmsService ersetzen oder für Tests ein Mock-Objekt verwenden möchten, müssen Sie den Code innerhalb von UserController ändern.



Dependency Injection löst dieses Problem. Anstatt Abhängigkeiten innerhalb der Struktur zu erstellen, „injizieren“ wir sie von außen. Die Grundidee: „Frage nicht, was du brauchst. Sage, was du brauchst, und erhalte es fertig.“



Manuelle Abhängigkeitsinjektion über den Konstruktor



Die einfachste und gebräuchlichste Methode der DI in Go ist die Übergabe von Abhängigkeiten über eine Konstruktorfunktion. Lassen Sie uns unser Beispiel umschreiben:



package main

import "fmt"

// Definieren eines Interfaces für Flexibilitättype Notifier interface { Send(to string, message string) error}

type EmailService struct{}

func (e *EmailService) Send(to string, message string) error { fmt.Printf("E-Mail an %s: %s", to, message) return nil}

type SmsService struct{}

func (s *SmsService) Send(to string, message string) error { fmt.Printf("SMS an %s: %s", to, message) return nil}

type UserController struct { notifier Notifier // Abhängigkeit über Interface}

// NewUserController – Konstruktor, der die Abhängigkeit entgegennimmtfunc NewUserController(n Notifier) *UserController { return &UserController{ notifier: n, }}

func (uc *UserController) RegisterUser(email string) { // ... Geschäftslogik uc.notifier.Send(email, "Willkommen!")}

func main() { // Abhängigkeit manuell injizieren emailNotifier := &EmailService{} controller := NewUserController(emailNotifier) controller.RegisterUser("user@example.com")

// Einfach die Implementierung wechseln smsNotifier := &SmsService{} controller2 := NewUserController(smsNotifier) controller2.RegisterUser("+123456789")}


Was hat sich geändert?

  • Wir haben ein Interface Notifier definiert. Jetzt weiß UserController nicht, welcher Dienst genau verwendet wird – E-Mail oder SMS.
  • Der Konstruktor NewUserController nimmt Notifier als Argument entgegen. Das ist die Abhängigkeitsinjektion.
  • In main entscheiden wir selbst, welche Implementierung wir übergeben.


Dieser Ansatz macht den Code flexibel, testbar und entspricht dem Prinzip der Inversion of Control.

Blogs

Buchempfehlungen