Mascheramento dei metodi embedded
Fa parte della sezione Programmazione orientata agli oggetti del percorso GO di Coddy. Lezione 39 di 107.
A volte è necessario che la struct esterna fornisca una propria implementazione di un metodo già presente nel tipo incorporato. Questo si chiama shadowing e consente di sovrascrivere i metodi promossi con un comportamento personalizzato.
Quando definisci un metodo sulla struct esterna con lo stesso nome di un metodo incorporato, prevale il metodo esterno:
type Animal struct {
Name string
}
func (a Animal) Speak() string {
return "Some sound"
}
type Dog struct {
Animal
Breed string
}
func (d Dog) Speak() string {
return "Woof!"
}
Ora, quando chiami Speak() su un Dog, viene usato il metodo esterno:
func main() {
d := Dog{Animal: Animal{Name: "Rex"}, Breed: "Labrador"}
fmt.Println(d.Speak()) // Woof! - Dog's method
fmt.Println(d.Animal.Speak()) // Some sound - Animal's method
}
Il metodo incorporato non è scomparso. Puoi ancora accedervi esplicitamente tramite il nome del tipo incorporato. Questo schema è utile quando vuoi personalizzare il comportamento mantenendo disponibile l'implementazione originale, magari per richiamarla dal tuo metodo di override:
func (d Dog) Speak() string {
return d.Animal.Speak() + " (but actually Woof!)"
}
L'ombreggiamento ti consente di controllare quale comportamento viene esposto, mantenendo al contempo l'accesso all'originale tramite qualificazione esplicita.
Sfida
FacileCostruiamo un sistema di notifiche in cui diversi canali di notifica possano personalizzare il modo in cui formattano e inviano i messaggi. Userai l'oscuramento dei metodi per consentire a canali specifici di sovrascrivere il comportamento predefinito, mantenendo comunque la possibilità di accedere all'implementazione originale quando necessario.
Organizzerai il codice in tre file:
base.go: crea una structBaseNotificationcon i campiTitleePriority(entrambi stringhe). Aggiungi un metodoFormat() stringche restituisca la notifica in un formato standard:[Priority] Title.channels.go: crea due tipi di canale di notifica che incorporanoBaseNotificatione oscurano il metodoFormatcon le proprie implementazioni:EmailNotificationcon un campoRecipient. Il suoFormat()dovrebbe restituireEmail to [Recipient]: [Priority] TitleSlackNotificationcon un campoChannel. Il suoFormat()dovrebbe chiamare il metodo incorporatoBaseNotification.Format()e anteporre#[Channel]:al risultato
main.go: leggi i dettagli delle notifiche dall'input, crea entrambi i tipi di notifica e mostra l'oscuramento stampando:- L'output formattato di
EmailNotification(usando il suo metodo oscurato) - Il formato di base di
EmailNotification(chiamando esplicitamente il metodo incorporato) - L'output formattato di
SlackNotification(che usa internamente il metodo di base)
- L'output formattato di
Verranno forniti i seguenti input:
- Riga 1: titolo della notifica
- Riga 2: livello di priorità
- Riga 3: destinatario dell'email
- Riga 4: nome del canale Slack
Ad esempio, dati Server Alert, HIGH, admin@company.com e ops-alerts, l'output dovrebbe essere:
Email to admin@company.com: HIGH Server Alert
[HIGH] Server Alert
#ops-alerts: [HIGH] Server AlertNota come EmailNotification sostituisca completamente la formattazione di base, mentre SlackNotification la arricchisca chiamando il metodo originale e aggiungendo il contesto del canale. Entrambi gli approcci dimostrano diversi modi di usare efficacemente l'oscuramento dei metodi.
Provalo tu
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
scanner := bufio.NewScanner(os.Stdin)
// Leggi il titolo della notifica
scanner.Scan()
title := scanner.Text()
// Leggi il livello di priorità
scanner.Scan()
priority := scanner.Text()
// Leggi il destinatario dell'email
scanner.Scan()
recipient := scanner.Text()
// Leggi il nome del canale Slack
scanner.Scan()
channel := scanner.Text()
// TODO: Crea un'istanza di EmailNotification con la notifica di base, il titolo, la priorità e il destinatario
// TODO: Crea un'istanza di SlackNotification con la notifica di base, il titolo, la priorità e il canale
// TODO: Stampa l'output formattato di EmailNotification (usando il suo metodo che nasconde quello incorporato)
// TODO: Stampa il formato di base di EmailNotification (chiamando esplicitamente il metodo incorporato)
// TODO: Stampa l'output formattato di SlackNotification
fmt.Println() // Segnaposto - rimuovere durante l'implementazione
}
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