Interface-Komposition und Best Practices
Kleine Interfaces und Dependency Inversion
Interface-Komposition und Best Practices ist eine kostenlose Go Academy-Lektion auf CoddyKit. Dies ist Lektion 4 von 4. Du kannst die komplette Lektion unten kostenlos lesen – dann übst du sie direkt im Browser mit einem integrierten Code-Editor und einem KI-Tutor rund um die Uhr. Sie ist Teil des Go Academy-Lernpfads, und dein Fortschritt wird über Web und CoddyKit-App synchronisiert. Der Go Academy-Kurs umfasst insgesamt 4 Lektionen.
Zusammensetzen von Interfaces
Go-Interfaces können andere Interfaces einbetten, um größere Interfaces zusammenzusetzen:
package main
import "io"
// io.ReadWriter composes Reader and Writer
type ReadWriter interface {
io.Reader
io.Writer
}
// Your own composition:
type Processor interface {
io.Reader
Process() error
io.Closer
}
func main() { _ = (*Processor)(nil) }Prinzip kleiner Interfaces
Die leistungsfähigsten Go-Interfaces haben ein oder zwei Methoden. Dadurch maximieren sie die Anzahl der Typen, die sie implementieren können:
io.Reader— 1 Methodeio.Writer— 1 Methodeerror— 1 Methodefmt.Stringer— 1 Methode
Große Interfaces lassen sich schwerer mocken und testen.
Dependency Inversion
Akzeptieren Sie in Funktionsparametern Interfaces statt konkreter Typen. Dadurch wird Ihr Code von bestimmten Implementierungen entkoppelt:
package main
import "fmt"
type Store interface {
Get(key string) (string, bool)
Set(key, val string)
}
func cache(s Store, key, value string) {
if _, ok := s.Get(key); !ok {
s.Set(key, value)
}
}
type MapStore struct{ m map[string]string }
func (ms *MapStore) Get(k string) (string, bool) { v, ok := ms.m[k]; return v, ok }
func (ms *MapStore) Set(k, v string) { ms.m[k] = v }
func main() {
s := &MapStore{m: map[string]string{}}
cache(s, "x", "hello")
v, _ := s.Get("x")
fmt.Println(v)
}Interface-Segregation
Teilen Sie große Interfaces in kleinere, klar abgegrenzte Interfaces auf. Clients hängen dann nur von den Methoden ab, die sie verwenden:
package main
// Bad: large interface forces all methods
type BigStorage interface {
Read(key string) string
Write(key, val string)
Delete(key string)
List() []string
Backup() error
}
// Good: small, focused interfaces
type Reader interface{ Read(key string) string }
type Writer interface{ Write(key, val string) }
type Lister interface{ List() []string }
func readAll(r Reader) {} // only needs Read
func main() { _ = readAll }Konkrete Typen zurückgeben
Konstruktoren sollten konkrete Typen und keine Interfaces zurückgeben. Aufrufer können einen konkreten Typ jederzeit einer Interface-Variablen zuweisen:
package main
type Logger interface{ Log(string) }
type ConsoleLogger struct{}
func (c *ConsoleLogger) Log(s string) {}
// Good: return concrete *ConsoleLogger
func NewConsoleLogger() *ConsoleLogger { return &ConsoleLogger{} }
// Avoid: return Logger (hides the concrete type)
// func NewConsoleLogger() Logger { return &ConsoleLogger{} }
func main() { _ = NewConsoleLogger() }Interface-Verschmutzung
Erstellen Sie nicht für jeden Typ vorsorglich ein Interface. Erstellen Sie Interfaces nur, wenn:
- Sie jetzt oder in absehbarer Zeit mehrere Implementierungen haben
- Sie die Abhängigkeit in Tests mocken müssen
- Sie eine Bibliothek entwickeln und die Aufrufer entkoppeln möchten
Interfaces zur Erweiterung einbetten
Betten Sie ein Interface ein, um optionale Methoden mit Standardimplementierungen hinzuzufügen:
package main
import "fmt"
type Handler interface{ Handle(msg string) }
type NamedHandler interface {
Handler
Name() string
}
func dispatch(h Handler) {
if nh, ok := h.(NamedHandler); ok {
fmt.Printf("[%s] ", nh.Name())
}
h.Handle("event")
}
type MyHandler struct{}
func (m MyHandler) Handle(msg string) { fmt.Println(msg) }
func (m MyHandler) Name() string { return "my" }
func main() { dispatch(MyHandler{}) }Mocking mit Interfaces
Definieren Sie Abhängigkeiten als Interfaces und injizieren Sie in Tests Mocks:
package main
import "fmt"
type Clock interface{ Now() int64 }
type MockClock struct{ T int64 }
func (m MockClock) Now() int64 { return m.T }
func isExpired(c Clock, expiresAt int64) bool {
return c.Now() > expiresAt
}
func main() {
mc := MockClock{T: 1000}
fmt.Println(isExpired(mc, 500)) // true
fmt.Println(isExpired(mc, 1500)) // false
}Interface- vs. Struct-Einbettung zur Wiederverwendung
Verwenden Sie die Interface-Einbettung zum Zusammensetzen von APIs und die Struct-Einbettung zur Wiederverwendung von Code. Sie dienen unterschiedlichen Zwecken und sollten nicht verwechselt werden.
Interface-Konformität zur Compile-Zeit erkennen
Verwenden Sie eine Compile-Time-Prüfung mit einem Blank Identifier, um zu verifizieren, dass Ihr Typ ein Interface erfüllt:
package main
type Doer interface{ Do() }
type MyType struct{}
func (m *MyType) Do() {}
// Compile-time check — no runtime cost
var _ Doer = (*MyType)(nil)
func main() {}Schnelltest
Wann sollten Sie in Go ein neues Interface definieren?
Zusammenfassung: Best Practices für Interfaces
Die wichtigsten Erkenntnisse:
- Halten Sie Interfaces klein — eine oder zwei Methoden
- Setzen Sie Interfaces aus kleineren Interfaces zusammen
- Akzeptieren Sie Interfaces und geben Sie konkrete Typen zurück
- Erstellen Sie Interfaces für Testbarkeit und mehrere Implementierungen
- Verwenden Sie eine Compile-Time-Prüfung durch Zuweisung an den Blank Identifier
Übungsaufgabe
Entwerfen Sie ein Notifier-Interface mit Notify(msg string) error. Implementieren Sie es für EmailNotifier und SMSNotifier. Schreiben Sie eine broadcast-Funktion, die an ein []Notifier sendet.
Häufig gestellte Fragen
Ist die Lektion „Interface-Komposition und Best Practices“ kostenlos?
Ja — der vollständige Text von „Interface-Komposition und Best Practices“ ist hier im Web kostenlos zu lesen. Um sie interaktiv zu üben (integrierter Code-Editor und 24/7 KI-Tutor) und den Rest des Go Academy-Kurses freizuschalten, upgrade auf CoddyKit PRO. Der Go Academy-Kurs umfasst insgesamt 4 Lektionen.
Was lerne ich in „Interface-Komposition und Best Practices“?
Kleine Interfaces und Dependency Inversion Du übst Go Academy mit praktischem Code, den du direkt im Browser ausführst, und ein 24/7 KI-Tutor beantwortet deine Fragen während du die Lektion bearbeitest.
Brauche ich Erfahrung, um Go Academy zu starten?
Keine Vorkenntnisse erforderlich. Go Academy auf CoddyKit ist für Anfänger bis fortgeschrittene Lernende strukturiert, sodass du hier starten oder von Anfang an beginnen und in deinem eigenen Tempo voranschreiten kannst. Dies ist Lektion 4 von 4.
Wie lange dauert die Lektion „Interface-Komposition und Best Practices“?
Die meisten CoddyKit-Lektionen dauern etwa 5–10 Minuten. Jede ist kompakt und interaktiv, sodass du stetig Fortschritte machst und genau dort weitermachst, wo du aufgehört hast – im Web und in der App.
Kann ich in dieser Go Academy-Lektion Code schreiben und ausführen?
Ja. Jede Go Academy-Lektion enthält einen integrierten Code-Editor, sodass du echten Code direkt in deinem Browser schreibst und ausführst und sofort KI-Feedback erhältst — ohne lokale Einrichtung erforderlich.
Alle Lektionen in diesem Kurs
- Interfaces definieren und implementieren
- Zentrale Interfaces der Standardbibliothek
- Typ-Assertions und Type-Switches
- Interface-Komposition und Best Practices