0Pricing
Go Academy · Lektion

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 Methode
  • io.Writer — 1 Methode
  • error — 1 Methode
  • fmt.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

  1. Interfaces definieren und implementieren
  2. Zentrale Interfaces der Standardbibliothek
  3. Typ-Assertions und Type-Switches
  4. Interface-Komposition und Best Practices
← Zurück zu Go Academy