Go Academy · Lekcja

Kompozycja interfejsów i dobre praktyki

Małe interfejsy i odwrócenie zależności

Lekcja 4 z 413 kroki

Kompozycja interfejsów i dobre praktyki to bezpłatna lekcja Go Academy na CoddyKit. To lekcja 4 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Go Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Go Academy zawiera 4 lekcji w sumie.

Kompozycja interfejsów

Interfejsy Go mogą osadzać inne interfejsy, aby tworzyć większe interfejsy:

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) }

Zasada małych interfejsów

Najbardziej użyteczne interfejsy Go mają jedną lub dwie metody. Maksymalizuje to liczbę typów, które mogą je implementować:

  • io.Reader — 1 metoda
  • io.Writer — 1 metoda
  • error — 1 metoda
  • fmt.Stringer — 1 metoda

Duże interfejsy są trudniejsze do mockowania i testowania.

Odwrócenie zależności

Przyjmuj interfejsy w parametrach funkcji zamiast typów konkretnych. Dzięki temu kod nie jest zależny od konkretnych implementacji:

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)
}

Segregacja interfejsów

Podziel duże interfejsy na mniejsze i ukierunkowane. Kod korzystający z interfejsu zależy tylko od używanych metod:

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 }

Zwracanie typów konkretnych

Konstruktory powinny zwracać typy konkretne, a nie interfejsy. Kod wywołujący zawsze może przypisać typ konkretny do zmiennej interfejsowej:

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() }

Nadmiar interfejsów

Nie twórz interfejsu dla każdego typu „na wszelki wypadek”. Twórz interfejsy tylko wtedy, gdy:

  • Masz już lub wkrótce będziesz mieć wiele implementacji
  • Potrzebujesz mockować zależność w testach
  • Tworzysz bibliotekę i chcesz oddzielić kod wywołujący od implementacji

Osadzanie interfejsów w celu rozszerzania

Osadź interfejs, aby dodać opcjonalne metody z implementacjami domyślnymi:

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{}) }

Mockowanie za pomocą interfejsów

Zdefiniuj zależności jako interfejsy; w testach wstrzykuj mocki:

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
}

Osadzanie interfejsów a struktur w celu ponownego użycia

Używaj osadzania interfejsów do komponowania API, a osadzania struktur do ponownego użycia kodu. Służą różnym celom i nie należy ich mylić.

Sprawdzanie zgodności z interfejsem w czasie kompilacji

Użyj sprawdzenia kompilacyjnego z pustym identyfikatorem, aby zweryfikować, czy typ spełnia wymagania interfejsu:

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() {}

Szybkie sprawdzenie

Kiedy należy definiować nowy interfejs w Go?

Podsumowanie: dobre praktyki dotyczące interfejsów

Najważniejsze informacje:

  • Utrzymuj małe interfejsy — jedna lub dwie metody
  • Komponuj interfejsy z mniejszych interfejsów
  • Przyjmuj interfejsy, zwracaj typy konkretne
  • Twórz interfejsy na potrzeby testowalności i wielu implementacji
  • Używaj sprawdzenia kompilacyjnego z przypisaniem do pustego identyfikatora

Zadanie praktyczne

Zaprojektuj interfejs Notifier z metodą Notify(msg string) error. Zaimplementuj go dla typów EmailNotifier i SMSNotifier. Napisz funkcję broadcast, która wysyła powiadomienia do elementów []Notifier.

Bezpłatny start

Ucz się Go dzięki korepetycjom AI — za darmo

Pisz i uruchamiaj kod w przeglądarce, otrzymuj natychmiastową pomoc od korepetytora AI dostępnego 24/7 i kontynuuj naukę w sieci lub w aplikacji.

Kursy
51
Lekcje
203

Często zadawane pytania

Czy lekcja „Kompozycja interfejsów i dobre praktyki” jest bezpłatna?

Tak — pełny tekst „Kompozycja interfejsów i dobre praktyki” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Go Academy, przejdź na CoddyKit PRO. Kurs Go Academy zawiera 4 lekcji w sumie.

Co nauczysz się w „Kompozycja interfejsów i dobre praktyki”?

Małe interfejsy i odwrócenie zależności Ćwiczysz Go Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć Go Academy?

Nie wymagamy żadnego doświadczenia. Go Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 4 z 4.

Ile czasu zajmuje lekcja „Kompozycja interfejsów i dobre praktyki”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji Go Academy?

Tak. Każda lekcja Go Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. Definiowanie i implementowanie interfejsów
  2. Podstawowe interfejsy biblioteki standardowej
  3. Asercje typów i przełączniki typów
  4. Kompozycja interfejsów i dobre praktyki
← Powrót do Go Academy