SOLID-Prinzipien in Go: Theorie und Praxis für Entwickler

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

Einführung: Warum SOLID in Go wichtig ist

SOLID ist eine Sammlung von fünf grundlegenden Prinzipien der objektorientierten Programmierung, die helfen, flexiblen, wartbaren und erweiterbaren Code zu erstellen. Obwohl Go keine klassische OOP-Sprache ist (es hat keine Klassen oder Vererbung), lassen sich diese Prinzipien dank Interfaces, Komposition und starker Typisierung perfekt anwenden. In diesem Artikel werden wir jedes SOLID-Prinzip mit Beispielen in Go durchgehen, damit Sie qualitativ hochwertigeren und skalierbareren Code schreiben können.

1. Single Responsibility Principle (SRP)

SRP besagt: "Ein Modul sollte nur einen Grund für eine Änderung haben". In Go bedeutet dies, dass eine Funktion, ein Struct oder ein Paket für eine klar definierte Aufgabe verantwortlich sein sollte.

Schlechtes Beispiel (SRP-Verletzung):

type Report struct {
    Title string
    Body  string
}

func (r *Report) Generate() string {
    return fmt.Sprintf("<h1>%s</h1><p>%s</p>", r.Title, r.Body)
}

func (r *Report) SaveToFile(filename string) error {
    return os.WriteFile(filename, []byte(r.Generate()), 0644)
}

func (r *Report) SendEmail(addr string) error {
    // E-Mail-Sendelogik
    return nil
}

Hier ist das Report-Struct verantwortlich für Generierung, Speicherung und Versand – drei verschiedene Gründe für eine Änderung.

Gutes Beispiel (SRP-Konformität):

type Report struct {
    Title string
    Body  string
}

func (r *Report) Generate() string {
    return fmt.Sprintf("<h1>%s</h1><p>%s</p>", r.Title, r.Body)
}

type ReportSaver struct{}

func (rs *ReportSaver) SaveToFile(report *Report, filename string) error {
    return os.WriteFile(filename, []byte(report.Generate()), 0644)
}

type EmailSender struct{}

func (es *EmailSender) Send(report *Report, addr string) error {
    // E-Mail-Sendelogik
    return nil
}

Jetzt hat jede Entität eine einzige Verantwortung: Generierung, Speicherung und Versand.

2. Open/Closed Principle (OCP)

OCP besagt: "Softwareentitäten sollten für Erweiterungen offen, aber für Modifikationen geschlossen sein". In Go wird dies durch Interfaces und Komposition erreicht.

Schlechtes Beispiel (OCP-Verletzung):

type PaymentProcessor struct{}

func (p *PaymentProcessor) Process(paymentType string, amount float64) {
    if paymentType == "credit_card" {
        // Kreditkartenabwicklung
    } else if paymentType == "paypal" {
        // PayPal-Abwicklung
    } else if paymentType == "crypto" {
        // Kryptowährungsabwicklung
    }
}

Beim Hinzufügen einer neuen Zahlungsart müsste die Process-Methode geändert werden.

Gutes Beispiel (OCP-Konformität):

type PaymentMethod interface {
    Pay(amount float64) error
}

type CreditCard struct{}
func (c *CreditCard) Pay(amount float64) error {
    // Kartenzahlungslogik
    return nil
}

type PayPal struct{}
func (p *PayPal) Pay(amount float64) error {
    // PayPal-Zahlungslogik
    return nil
}

type PaymentProcessor struct{}

func (pp *PaymentProcessor) Process(method PaymentMethod, amount float64) error {
    return method.Pay(amount)
}

Um eine neue Zahlungsmethode hinzuzufügen, implementieren Sie einfach das PaymentMethod-Interface, ohne vorhandenen Code zu berühren.

3. Liskov Substitution Principle (LSP)

LSP verlangt: "Objekte in einem Programm sollten durch Instanzen ihrer Subtypen ersetzt werden können, ohne die Korrektheit des Programms zu verändern". In Go betrifft dies die Implementierung von Interfaces.

Schlechtes Beispiel (LSP-Verletzung):

type Bird interface {
    Fly() error
}

type Penguin struct{}
func (p *Penguin) Fly() error {
    return errors.New("Pinguine können nicht fliegen")
}

func LetBirdFly(b Bird) {                

Blogs

Buchempfehlungen