Collezioni polimorfiche
Fa parte della sezione Programmazione orientata agli oggetti del percorso GO di Coddy. Lezione 44 di 107.
Una delle applicazioni più potenti delle interfacce è memorizzare tipi diversi nella stessa raccolta. Una slice di un tipo di interfaccia può contenere qualsiasi valore che soddisfi tale interfaccia, consentendoti di raggruppare tipi correlati ma diversi.
Considera uno scenario in cui devi gestire varie forme. Invece di slice separate per ogni tipo, puoi usare una singola slice del tipo interfaccia:
type Shape interface {
Area() float64
}
type Circle struct{ Radius float64 }
func (c Circle) Area() float64 { return 3.14159 * c.Radius * c.Radius }
type Rectangle struct{ Width, Height float64 }
func (r Rectangle) Area() float64 { return r.Width * r.Height }
func main() {
shapes := []Shape{
Circle{Radius: 5},
Rectangle{Width: 4, Height: 3},
Circle{Radius: 2},
}
for _, s := range shapes {
fmt.Printf("Area: %.2f\n", s.Area())
}
}
La slice shapes contiene sia cerchi che rettangoli. Durante l'iterazione, ogni elemento risponde a Area() in base al suo tipo effettivo. Questa è la polimorfia applicata alle collezioni: lo stesso ciclo gestisce uniformemente tutti i tipi di forme.
Le collezioni polimorfiche sono essenziali quando si creano sistemi che elaborano elementi diversi: un sistema di notifiche che invia email e messaggi SMS, un gioco che aggiorna diversi tipi di nemici o un elaboratore di documenti che gestisce più formati di file. Alla collezione non interessano i tipi specifici: conta solo che ogni elemento fornisca il comportamento richiesto.
Sfida
FacileCreiamo un sistema di gestione delle attività che gestisce diversi tipi di attività tramite un'interfaccia unificata. Creerai vari tipi di attività e le elaborerai tutte insieme in una raccolta polimorfica.
Organizzerai il codice in tre file:
task.go: Definisci un'interfacciaTaskche richiede un metodoSummary() string. Questa interfaccia sarà il contratto comune che tutti i tipi di attività devono rispettare.types.go: Crea tre diversi tipi di attività che implementano ciascuno l'interfacciaTask:BugFixcon i campiID(string) eSeverity(string). Il suoSummary()restituisceBug #[ID] ([Severity])Featurecon i campiName(string) ePoints(int). Il suoSummary()restituisceFeature: [Name] - [Points] ptsDocumentationcon il campoTopic(string). Il suoSummary()restituisceDocs: [Topic]
main.go: Crea una funzione chiamataPrintBacklogche accetta una slice diTaske stampa il riepilogo di ogni attività su una riga separata. Leggi i dettagli delle attività dall'input, crea un'attività per ciascun tipo, raccoglile tutte in un'unica slice[]Taske passala aPrintBacklog.
Verranno forniti i seguenti input:
- Riga 1: ID del bug
- Riga 2: Gravità del bug
- Riga 3: Nome della funzionalità
- Riga 4: Punti della funzionalità (intero)
- Riga 5: Argomento della documentazione
Ad esempio, dati 1042, critical, Dark Mode, 8 e API Reference, l'output dovrebbe essere:
Bug #1042 (critical)
Feature: Dark Mode - 8 pts
Docs: API ReferenceIl vantaggio è che PrintBacklog non ha bisogno di una logica separata per bug, funzionalità o documentazione. Itera semplicemente attraverso la slice e chiama Summary() su ciascun elemento. Ogni tipo di attività risponde con il proprio formato specifico, dimostrando come le raccolte polimorfiche permettano di elaborare tipi diversi in modo uniforme.
Provalo tu
package main
import (
"fmt"
)
// TODO: Crea una funzione PrintBacklog che accetti uno slice di Task
// e stampi il riepilogo di ogni attività su una riga separata
func main() {
// Leggi l'input
var bugID string
var bugSeverity string
var featureName string
var featurePoints int
var docTopic string
fmt.Scanln(&bugID)
fmt.Scanln(&bugSeverity)
fmt.Scanln(&featureName)
fmt.Scanln(&featurePoints)
fmt.Scanln(&docTopic)
// TODO: Crea un'istanza per ogni tipo di attività (BugFix, Feature, Documentation)
// TODO: Raccogli tutte le attività in un unico slice []Task
// TODO: Chiama PrintBacklog con lo slice delle attività
}
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