Composizione di interfacce
Fa parte della sezione Programmazione orientata agli oggetti del percorso GO di Coddy. Lezione 31 di 107.
Go ti consente di creare interfacce più grandi componendo interfacce più piccole. Invece di definire un’unica grande interfaccia con molti metodi, incorpori interfacce esistenti nella definizione di una nuova interfaccia.
type Reader interface {
Read() string
}
type Writer interface {
Write(data string)
}
// ReadWriter combina entrambe le interfacce
type ReadWriter interface {
Reader
Writer
}L'interfaccia ReadWriter ora richiede entrambi i metodi Read() e Write(). Qualsiasi tipo che implementi entrambi i metodi soddisfa ReadWriter, oltre a soddisfare individualmente Reader e Writer.
type File struct {
Name string
}
func (f File) Read() string { return "file content" }
func (f File) Write(data string) { fmt.Println("Writing:", data) }
func Process(rw ReadWriter) {
content := rw.Read()
rw.Write(content)
}
func main() {
f := File{Name: "data.txt"}
Process(f) // File soddisfa ReadWriter
}Questo approccio di composizione mantiene le interfacce piccole e mirate. Puoi combinarle come necessario, creando contratti precisi per le tue funzioni. La libreria standard di Go usa ampiamente questo schema, ad esempio io.ReadWriter, che combina io.Reader e io.Writer.
Sfida
FacileCostruiamo un sistema di riproduzione multimediale che mostri la composizione delle interfacce. Creerai interfacce piccole e mirate, per poi combinarle in un’interfaccia composta più potente che un singolo tipo può soddisfare.
Organizzerai il codice in due file:
media.go: definisci tre interfacce e una struct che le implementa tutte:- Un’interfaccia
Playercon un metodoPlay() string - Un’interfaccia
Recordercon un metodoRecord(content string) string - Un’interfaccia
MediaDeviceche compone siaPlayersiaRecorder - Una struct
SmartDevicecon un campoNameche implementa tutti i metodi richiesti
- Un’interfaccia
main.go: crea funzioni che mostrino come lo stessoSmartDevicepossa essere usato attraverso diversi tipi di interfaccia. Scrivi tre funzioni:UsePlayerche accetta unPlayere chiama il suo metodoPlayUseRecorderche accetta unRecordere una stringa di contenuto, quindi chiamaRecordUseMediaDeviceche accetta unMediaDevicee una stringa di contenuto, quindi chiama siaRecordsiaPlay
SmartDevicee mostra come usarlo attraverso tutti e tre i tipi di interfaccia.
Verranno forniti i seguenti input:
- Riga 1: nome del dispositivo
- Riga 2: contenuto da registrare
I tuoi metodi devono restituire stringhe nei seguenti formati:
Play():[Name] is playingRecord(content):[Name] recorded: [content]
Per esempio, dati MyPhone e voice memo, il tuo output dovrebbe essere:
MyPhone is playing
MyPhone recorded: voice memo
MyPhone recorded: voice memo
MyPhone is playingLe prime due righe mostrano il dispositivo usato attraverso le singole interfacce (Player e Recorder). Le ultime due righe mostrano il dispositivo usato attraverso l’interfaccia composta MediaDevice, che richiede entrambe le funzionalità. Nota come il tuo singolo SmartDevice soddisfi tutte e tre le interfacce perché dispone di entrambi i metodi richiesti.
Provalo tu
package main
import (
"bufio"
"fmt"
"os"
)
// TODO: Implementa UsePlayer in modo che accetti un Player e chiami il suo metodo Play
// Deve stampare il risultato di Play()
// TODO: Implementa UseRecorder in modo che accetti un Recorder e una stringa content
// Deve stampare il risultato di Record(content)
// TODO: Implementa UseMediaDevice in modo che accetti un MediaDevice e una stringa content
// Deve stampare il risultato di Record(content) e poi di Play()
func main() {
scanner := bufio.NewScanner(os.Stdin)
scanner.Scan()
deviceName := scanner.Text()
scanner.Scan()
content := scanner.Text()
// TODO: Crea uno SmartDevice con il nome fornito
// TODO: Usa il dispositivo tramite l'interfaccia Player
// TODO: Usa il dispositivo tramite l'interfaccia Recorder
// TODO: Usa il dispositivo tramite l'interfaccia MediaDevice
_ = deviceName
_ = content
fmt.Println("Implement the solution")
}
Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.
Tutte le lezioni di Programmazione orientata agli oggetti
1Fondamenti di OOP in Go
File esterniWorkspace e moduli GoPacchetti e importazioniNomi esportati e non esportatiIntroduzione all’OOP in GoGli struct come classiDefinire metodi sugli structReceiver con puntatore vs receiver con valoreInizializzazione degli structFunzioni costruttriciRiepilogo - Calcolatrice semplice4Interfacce
Introduzione alle interfacceImplementazione implicitaL’interfaccia come contrattoInterfaccia vuota (any)Asserzione di tipoSwitch sul tipoComposizione di interfacceInterfacce Stringer ed ErrorRipasso - Calcolatore di forme7Incapsulamento
Campi esportati e non esportatiIncapsulamento a livello di packageMetodi Getter e SetterNascondimento delle informazioni in GoRiepilogo - Registri degli studenti10Tipi generici (Go 1.18+)
Introduzione ai tipi genericiParametri di tipoVincoli di tipoStruct genericheSoluzione alternativa per i metodi genericiRiepilogo - Collezione generica13Modelli di progettazione Parte 1
Introduzione ai modelli di progettazioneModello SingletonModello FactoryModello Abstract FactoryModello ObserverModello Strategy2Approfondimento su tipi e struct
Tipi di base e compostiDefinizioni di tipi personalizzatiTag delle structStruct anonimeStruct annidateValori zero e predefinitiRipasso - Rubrica5Composizione invece dell'ereditarietà
Perché Go non ha l'ereditarietàFondamenti dell'embedding delle structPromozione dei metodiEmbedding di più structEmbedding e aggregazione a confrontoMascheramento dei metodi embeddedRiepilogo: gerarchia dei dipendenti8Gestione degli errori e OOP
L'interfaccia errorTipi di errore personalizzatiWrapping degli errori (fmt.Errorf)Errori sentinellaerrors.Is() ed errors.As()Panic, Defer e RecoverRiepilogo - Parser di file11Libreria standard e OOP
io.Reader e io.Writersort.InterfaceInterfaccia fmt.Stringerencoding/json con le structInterfaccia http.HandlerRipasso - modelli REST API14Modelli di progettazione – Parte 2
Pattern CommandPattern AdapterPattern DecoratorPattern Template MethodPattern StatePattern CompositeMiddleware come Decorator3Puntatori e memoria
Concetti base dei puntatori in GoPuntatori a structPassaggio per valore vs per riferimentoLa funzione new()Garbage collection in GoRiepilogo - Costruttore di liste concatenate6Polimorfismo in Go
Polimorfismo tramite interfacceDuck typing in GoRegole di soddisfacimento delle interfacceCollezioni polimorficheIniezione delle dipendenzeRiepilogo - Elaboratore di pagamenti9Concorrenza e OOP
Basi delle goroutineCanali e comunicazioneCanali bufferizzati vs non bufferizzatiIstruzione selectsync.Mutex e sync.RWMutexsync.WaitGroupProgettazione di struct thread-safeRiepilogo: worker poolEsercitati da solo: Compilatore Go online