Go: Funktional oder OOP? Den Programmierstil wählen

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

Einleitung: Die ewige Debatte in der Go-Welt

\n\n

Go ist eine Sprache, die mit Konventionen gebrochen hat. Sie verzeiht keine übermäßige Komplexität, gibt dem Entwickler aber unglaubliche Freiheit. Jeder, der anfängt, in Go zu schreiben (oder von Python oder Java umsteigt), stößt früher oder später auf eine Wand: „Wie macht man es richtig? Wie in Java mit Klassen und Vererbung schreiben oder wie in Haskell mit Funktionen ohne Seiteneffekte?“

\n\n

Spoiler: Go ist weder eine rein objektorientierte noch eine rein funktionale Sprache. Es ist pragmatisch. Aber das bedeutet nicht, dass Sie beide Paradigmen nicht nutzen können (und sollten). In diesem Artikel werden wir untersuchen, wie man funktionale und objektorientierte Ansätze in Go kombiniert, damit Ihr Code lesbar, testbar und schnell ist. Wir werden keine Vorträge halten, sondern uns reale Beispiele und Antipatterns ansehen.

\n\n

Wenn Sie nach Best Practices für Go suchen und verstehen möchten, wie man sauberen Code in dieser Sprache schreibt, sind Sie hier genau richtig.

\n\n

1. Objektorientierter Ansatz in Go: Ohne Klassen, aber mit Seele

\n\n

Viele denken, dass es in Go kein OOP gibt, weil es kein class gibt. Das ist ein Mythos. OOP in Go basiert auf zwei Säulen: Strukturen (structs) und Schnittstellen (interfaces). Es gibt keine Vererbung, aber dafür Komposition, die die Sprachschöpfer für flexibler halten.

\n\n

Strukturen und Methoden

\n

Sie können Methoden für jeden Typ definieren. Das ist die Grundlage objektorientierten Codes.

\n\n
package main\n\nimport "fmt"\n\n// Definieren einer Schnittstelle (Vertrag)\ntype Notifier interface {\n    Send(message string) error\n}\n\n// Struktur, die die Schnittstelle implementiert\ntype EmailNotifier struct {\n    Email string\n}\n\n// Methode für EmailNotifier\nfunc (e EmailNotifier) Send(message string) error {\n    fmt.Printf("Sende E-Mail an %s: %s\\n", e.Email, message)\n    return nil\n}\n\n// Eine weitere Struktur\ntype SMSNotifier struct {\n    Phone string\n}\n\nfunc (s SMSNotifier) Send(message string) error {\n    fmt.Printf("Sende SMS an %s: %s\\n", s.Phone, message)\n    return nil\n}\n\n// Funktion, die jeden Notifier akzeptiert (Polymorphie)\nfunc AlertAll(notifiers []Notifier, msg string) {\n    for _, n := range notifiers {\n        n.Send(msg)\n    }\n}\n\nfunc main() {\n    notifiers := []Notifier{\n        EmailNotifier{Email: "user@example.com"},\n        SMSNotifier{Phone: "+1234567890"},\n    }\n    AlertAll(notifiers, "Server ausgefallen!")\n}
\n\n

Vorteile von OOP in Go:

\n
    \n
  • Polymorphie durch Schnittstellen. Sie schreiben einmal die Funktion AlertAll, und sie funktioniert mit jedem Typ, der Notifier implementiert. Das ist lose Kopplung.
  • \n
  • Zustand. Strukturen sind ideal für Datenmodelle (User, Order, Config).
  • \n
  • Kapselung. Felder mit Kleinbuchstaben sind privat, mit Großbuchstaben öffentlich. Einfach und effektiv.
  • \n
\n\n

Nachteile:

\n
    \n
  • Man kann leicht in den „Java-Stil“ verfallen: tiefe Hierarchien erstellen, obwohl Go diese nicht unterstützt.
  • \n
  • Mutabilität (Zustandsänderung) erschwert das Testen und Debuggen.
  • \n
\n\n

2. Funktionale Programmierung in Go: Reinheit für Geschwindigkeit

\n\n

Der funktionale Stil in Go ist keine Lambda-Rechnung, sondern eher eine Reihe von Prinzipien: minimale Seiteneffekte, Unveränderlichkeit, Funktionen als Argumente. Mit dem Aufkommen von Generics (Go 1.18+) ist dieser Stil leistungsfähiger geworden.

\n\n

Reine Funktionen und Unveränderlichkeit

\n

Die Hauptregel der Funktionalität: Eine Funktion erhält Daten, gibt neue Daten zurück, ändert aber nichts außerhalb.

\n\n
package main\n\nimport "fmt"\n\n// Schlecht: Mutieren des eingehenden Slices (Seiteneffekt)\nfunc BadAddPrefix(users []string, prefix string) {\n    for i := range users {\n        users[i] = prefix + users[i]\n    }\n}\n\n// Gut: Rückgabe eines neuen Slices (reine Funktion)\                

Blogs

Buchempfehlungen