SOLID Design in Go
Grace Collins
Solutions Engineer · Leapcell

Im Softwareentwicklung ist das Erstellen von wartbarem, skalierbarem und robustem Code das ultimative Ziel. Die SOLID-Prinzipien, die von Robert C. Martin (auch bekannt als Uncle Bob) vorgeschlagen wurden, bieten eine Grundlage für das Erreichen dieses Ziels. Wie können diese Prinzipien auf die Programmiersprache Go angewendet werden? Go ist bekannt für seine Einfachheit und seinen Pragmatismus und ermöglicht es uns, zu untersuchen, wie sein idiomatischer Stil mit den SOLID-Prinzipien übereinstimmt, um saubere und effiziente Software zu erstellen.
Single Responsibility Principle (SRP)
„Eine Klasse sollte nur einen Grund haben, sich zu ändern.“
In Go bedeutet SRP das Entwerfen von Funktionen, Strukturen und Paketen mit einer einzigen Verantwortung. Dies stellt sicher, dass der Code leichter zu verstehen, zu testen und zu warten ist.
Beispiel:
Verstoß gegen SRP:
func (us *UserService) RegisterUser(username, password string) error { // Benutzer in der Datenbank speichern // Bestätigungs-E-Mail senden // Registrierungsereignis protokollieren return nil }
Diese Funktion übernimmt mehrere Verantwortlichkeiten: das Speichern eines Benutzers, das Senden einer E-Mail und das Protokollieren eines Ereignisses. Änderungen in diesen Bereichen würden eine Änderung dieser Funktion erfordern.
Befolgen von SRP:
type UserService struct { db Database email EmailService logger Logger } func (us *UserService) RegisterUser(username, password string) error { if err := us.db.SaveUser(username, password); err != nil { return err } if err := us.email.SendConfirmation(username); err != nil { return err } us.logger.Log("Benutzer registriert: " + username) return nil }
Hier wird jede Verantwortung an eine bestimmte Komponente delegiert, wodurch der Code modular und testbar wird.
Open/Closed Principle (OCP)
„Software-Entitäten sollen für Erweiterungen offen, aber für Änderungen geschlossen sein.“
Go implementiert OCP durch Schnittstellen und Komposition, wodurch das Verhalten erweitert werden kann, ohne vorhandenen Code zu ändern.
Beispiel:
Verstoß gegen OCP:
func (p *PaymentProcessor) ProcessPayment(method string) { if method == "credit_card" { fmt.Println("Verarbeitung der Kreditkartenzahlung") } else if method == "paypal" { fmt.Println("Verarbeitung der PayPal-Zahlung") } }
Das Hinzufügen einer neuen Zahlungsmethode erfordert eine Änderung der Funktion ProcessPayment
, was gegen OCP verstößt.
Befolgen von OCP:
type PaymentMethod interface { Process() } type CreditCard struct {} func (cc CreditCard) Process() { fmt.Println("Verarbeitung der Kreditkartenzahlung") } type PayPal struct {} func (pp PayPal) Process() { fmt.Println("Verarbeitung der PayPal-Zahlung") } func (p PaymentProcessor) ProcessPayment(method PaymentMethod) { method.Process() }
Das Hinzufügen einer neuen Zahlungsmethode erfordert jetzt nur noch die Implementierung der Schnittstelle PaymentMethod
, ohne Änderungen am bestehenden Code.
Liskov Substitution Principle (LSP)
„Subtypen müssen durch ihre Basistypen ersetzbar sein.“
In Go wird LSP erreicht, indem Schnittstellen entworfen werden, die sich auf das Verhalten und nicht auf die Struktur konzentrieren.
Beispiel:
Verstoß gegen LSP:
type Rectangle struct { Width, Height float64 } type Square struct { Side float64 } func SetDimensions(shape *Rectangle, width, height float64) { shape.Width = width shape.Height = height }
Das Übergeben eines Square
an diese Funktion würde seine Einschränkungen verletzen, da die Breite und Höhe eines Quadrats immer gleich sein müssen.
Befolgen von LSP:
type Shape interface { Area() float64 } type Rectangle struct { Width, Height float64 } func (r Rectangle) Area() float64 { return r.Width * r.Height } type Square struct { Side float64 } func (s Square) Area() float64 { return s.Side * s.Side } func PrintArea(shape Shape) { fmt.Printf("Fläche: %.2f\n", shape.Area()) }
Sowohl Rectangle
als auch Square
implementieren Shape
, ohne ihre Einschränkungen zu verletzen, wodurch die Ersetzbarkeit sichergestellt wird.
Interface Segregation Principle (ISP)
„Clients sollten nicht gezwungen werden, von Schnittstellen abzuhängen, die sie nicht verwenden.“
Go’s Lightweight-Schnittstellen stimmen auf natürliche Weise mit ISP überein und fördern kleine und fokussierte Schnittstellen.
Beispiel:
Verstoß gegen ISP:
type Worker interface { Work() Eat() Sleep() }
Ein Roboter, der diese Schnittstelle implementiert, würde am Ende ungenutzte Methoden wie Eat
undSleep
enthalten.
Befolgen von ISP:
type Worker interface { Work() } type Eater interface { Eat() } type Sleeper interface { Sleep() }
Jeder Typ implementiert nur die Schnittstellen, die er benötigt, wodurch unnötige Abhängigkeiten vermieden werden.
Dependency Inversion Principle (DIP)
„High-Level-Module sollten von Abstraktionen und nicht von Details abhängen.“
Go’s Schnittstellen erleichtern das Entkoppeln von High-Level-Logik von Low-Level-Implementierungen.
Beispiel:
Verstoß gegen DIP:
type NotificationService struct { emailSender EmailSender } func (ns *NotificationService) NotifyUser(message string) { ns.emailSender.SendEmail(message) }
Hier ist NotificationService
eng an EmailSender
gekoppelt.
Befolgen von DIP:
type Notifier interface { Notify(message string) } type NotificationService struct { notifier Notifier } func (ns *NotificationService) NotifyUser(message string) { ns.notifier.Notify(message) }
Dies ermöglicht das Ersetzen von EmailSender
durch andere Implementierungen (z. B. SMSSender
), ohne NotificationService
zu ändern.
Fazit
Durch die Anwendung der SOLID-Prinzipien können Go-Entwickler sauberen, wartbaren und erweiterbaren Code schreiben. Beginnen Sie klein, refaktorieren Sie häufig und lassen Sie sich von Go’s Einfachheit zu einem besseren Softwaredesign führen.
Wir sind Leapcell, Ihre erste Wahl für das Hosten von Go-Projekten.
Leapcell ist die Next-Gen Serverless-Plattform für Webhosting, asynchrone Aufgaben und Redis:
Multi-Language Support
- Entwickeln Sie mit Node.js, Python, Go oder Rust.
Stellen Sie unbegrenzt Projekte kostenlos bereit
- Zahlen Sie nur für die Nutzung – keine Anfragen, keine Gebühren.
Unschlagbare Kosteneffizienz
- Pay-as-you-go ohne Leerlaufgebühren.
- Beispiel: 25 USD unterstützen 6,94 Millionen Anfragen bei einer durchschnittlichen Antwortzeit von 60 ms.
Optimierte Entwicklererfahrung
- Intuitive Benutzeroberfläche für mühelose Einrichtung.
- Vollautomatische CI/CD-Pipelines und GitOps-Integration.
- Echtzeitmetriken und -protokollierung für umsetzbare Erkenntnisse.
Mühelose Skalierbarkeit und hohe Leistung
- Auto-Scaling zur einfachen Bewältigung hoher Parallelität.
- Kein operativer Overhead – konzentrieren Sie sich einfach auf den Aufbau.
Erfahren Sie mehr in der Dokumentation!
Folgen Sie uns auf X: @LeapcellHQ