Go Academy · Lezione

Composizione delle interfacce e buone pratiche

Interfacce piccole e inversione delle dipendenze

Lezione 4 di 413 passaggi

Composizione delle interfacce e buone pratiche è una lezione Go Academy gratuita su CoddyKit. Questa è la lezione 4 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento Go Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso Go Academy include 4 lezioni in totale.

Composizione delle interfacce

Le interfacce Go possono incorporare altre interfacce per comporne di più ampie:

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

Principio delle interfacce piccole

Le interfacce Go più efficaci hanno uno o due metodi. In questo modo si massimizza il numero di tipi che possono soddisfarle:

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

Le interfacce ampie sono più difficili da simulare e testare.

Inversione delle dipendenze

Accetti le interfacce nei parametri delle funzioni invece dei tipi concreti. In questo modo il codice non dipende da implementazioni specifiche:

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

Segregazione delle interfacce

Divida le interfacce ampie in interfacce più piccole e mirate. I client dipendono solo dai metodi che utilizzano:

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 }

Restituzione di tipi concreti

I costruttori dovrebbero restituire tipi concreti, non interfacce. I chiamanti possono sempre assegnare un tipo concreto a una variabile di interfaccia:

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

Inquinamento delle interfacce

Non crei un'interfaccia per ogni tipo "per sicurezza". Crei interfacce solo quando:

  • Ha già, o avrà presto, più implementazioni
  • Deve simulare la dipendenza nei test
  • Sta sviluppando una libreria e vuole disaccoppiare i chiamanti

Incorporare interfacce per l'estensione

Incorpori un'interfaccia per aggiungere metodi opzionali con implementazioni predefinite:

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 con le interfacce

Definisca le dipendenze come interfacce e inietti i mock nei test:

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
}

Incorporamento di interfacce e struct per il riutilizzo

Utilizzi l'incorporamento delle interfacce per comporre le API e l'incorporamento delle struct per riutilizzare il codice. Hanno scopi diversi e non devono essere confusi.

Rilevare la conformità a un'interfaccia in fase di compilazione

Utilizzi un controllo in fase di compilazione con l'identificatore vuoto per verificare che il tipo soddisfi un'interfaccia:

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

Verifica rapida

Quando dovrebbe definire una nuova interfaccia in Go?

Riepilogo: best practice per le interfacce

Punti chiave:

  • Mantenga le interfacce piccole: uno o due metodi
  • Componga le interfacce a partire da interfacce più piccole
  • Accetti interfacce e restituisca tipi concreti
  • Crei interfacce per facilitare i test e supportare più implementazioni
  • Utilizzi un controllo in fase di compilazione tramite assegnazione all'identificatore vuoto

Esercizio

Progetti un'interfaccia Notifier con Notify(msg string) error. La implementi per EmailNotifier e SMSNotifier. Scriva una funzione broadcast che invii notifiche a un []Notifier.

Gratis per iniziare

Impara Go con un tutor IA — gratis

Scrivi ed esegui vero codice nel tuo browser, ricevi aiuto istantaneo da un tutor IA disponibile 24/7, e riprendi da dove hai lasciato sul web o nell'app.

Corsi
51
Lezioni
203

Domande Frequenti

La lezione «Composizione delle interfacce e buone pratiche» è gratuita?

Sì — il testo completo di «Composizione delle interfacce e buone pratiche» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso Go Academy, passa a CoddyKit PRO. Il corso Go Academy include 4 lezioni in totale.

Cosa imparerò in «Composizione delle interfacce e buone pratiche»?

Interfacce piccole e inversione delle dipendenze Eserciti Go Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.

Ho bisogno di esperienza per iniziare Go Academy?

Non è richiesta alcuna esperienza precedente. Go Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 4 di 4.

Quanto tempo richiede la lezione «Composizione delle interfacce e buone pratiche»?

La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.

Posso scrivere ed eseguire codice in questa lezione Go Academy?

Sì. Ogni lezione Go Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.

Tutte le lezioni di questo corso

  1. Definire e implementare le interfacce
  2. Interfacce fondamentali della libreria standard
  3. Asserzioni di tipo e switch sul tipo
  4. Composizione delle interfacce e buone pratiche
← Torna a Go Academy