SOLID-Prinzipien in Go: Fortgeschrittenes Handbuch mit Beispielen

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

SOLID-Prinzipien in Go: Fortgeschrittenes Niveau



SOLID – das sind fünf fundamentale Prinzipien des objektorientierten Designs, die helfen, flexiblen, wartbaren und skalierbaren Code zu erstellen. Im Kontext von Go, einer Sprache mit einer einzigartigen Philosophie der Komposition statt Vererbung, erfordert die Anwendung von SOLID einen besonderen Ansatz. In diesem Artikel werden wir jedes Prinzip auf fortgeschrittenem Niveau mit realen Beispielen und für die Go-Community typischen Antipatterns analysieren.



1. Single Responsibility Principle (SRP) in Go



Das Prinzip der einzigen Verantwortung besagt: Eine Klasse (Struktur) sollte nur einen Grund für eine Änderung haben. In Go wird dies oft in Utility-Paketen und "göttlichen Objekten" verletzt.



Antipattern: Struktur mit mehreren Zuständigkeiten



type UserService struct {    db *sql.DB    cache *redis.Client    logger *log.Logger}

func (s *UserService) CreateUser(ctx context.Context, u User) error { // 1. Validierung // 2. Passwort-Hashing // 3. Speichern in der DB // 4. E-Mail senden // 5. Logging return nil}


Lösung: Teilen Sie die Verantwortlichkeiten in separate Dienste auf und verwenden Sie Komposition.



type UserValidator interface {    Validate(u User) error}

type PasswordHasher interface { Hash(password string) (string, error)}

type UserRepository interface { Save(ctx context.Context, u User) error}

type EmailSender interface { SendWelcomeEmail(ctx context.Context, email string) error}

type UserService struct { validator UserValidator hasher PasswordHasher repo UserRepository emailSender EmailSender logger Logger}


Jede Komponente hat jetzt nur einen Grund für eine Änderung, was das Testen und die Wartung vereinfacht.



2. Open-Closed Principle (OCP) durch Interfaces



Das Prinzip der Offenheit/Geschlossenheit: Entitäten sollten für Erweiterungen offen, aber für Modifikationen geschlossen sein. In Go wird dies durch Interfaces und Dependency Injection erreicht.



Schlechtes Beispiel: Feste Kopplung



type PaymentProcessor struct {    paypalAPI *PayPalAPI}

func (p *PaymentProcessor) Process(amount float64) error { return p.paypalAPI.Charge(amount)}


Wenn Stripe hinzugefügt werden soll, muss der Code geändert werden.



Richtiger Ansatz: Interface + Strategie



type PaymentGateway interface {    Charge(amount float64) error    Refund(transactionID string) error}

type PayPalGateway struct{ /* ... */ }type StripeGateway struct{ /* ... */ }

func (p *PayPalGateway) Charge(amount float64) error { /* ... */ }func (s *StripeGateway) Charge(amount float64) error { /* ... */ }

type PaymentService struct { gateway PaymentGateway}

func NewPaymentService(gw PaymentGateway) *PaymentService { return &PaymentService{gateway: gw}}


Jetzt können neue Zahlungsgateways hinzugefügt werden, ohne PaymentService zu ändern.



3. Liskov Substitution Principle (LSP) im Kontext von Go



Das Substitutionsprinzip von Barbara Liskov: Objekte in einem Programm sollten durch Instanzen ihrer Subtypen ersetzt werden können, ohne die Korrektheit des Programms zu beeinträchtigen. In Go, wo es keine klassische Vererbung gibt, zeigt sich LSP durch Interface-Verträge.



Typische Verletzung: Interface mit überflüssigen Methoden



type Bird interface {    Fly() error    Swim() error}

type Penguin struct{}

func (p *Penguin) Fly() error { return errors.New("penguins can't fly")}

func (p *Penguin) Swim() error { return nil}


Hier kann Penguin Fly() nicht korrekt implementieren, was LSP verletzt.



Lösung: Aufteilung der Interfaces



type Flyer interface {    Fly() error}

type Swimmer interface { S

Blogs

Buchempfehlungen