Ocultação de métodos incorporados
Parte da seção Programação Orientada a Objetos do Journey de GO da Coddy. Lição 39 de 107.
Às vezes, você precisa que a struct externa forneça sua própria implementação de um método que o tipo incorporado já possui. Isso é chamado de sombreamento e permite substituir métodos promovidos por um comportamento personalizado.
Quando você define um método na estrutura externa com o mesmo nome de um método incorporado, o método externo tem precedência:
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!"
}
Agora, quando você chama Speak() em um Dog, o método externo é usado:
func main() {
d := Dog{Animal: Animal{Name: "Rex"}, Breed: "Labrador"}
fmt.Println(d.Speak()) // Woof! - método de Dog
fmt.Println(d.Animal.Speak()) // Algum som - método de Animal
}
O método incorporado não desapareceu. Você ainda pode acessá-lo explicitamente por meio do nome do tipo incorporado. Esse padrão é útil quando você quer personalizar o comportamento mantendo a implementação original disponível, talvez para chamá-la de dentro do seu método sobrescrito:
func (d Dog) Speak() string {
return d.Animal.Speak() + " (but actually Woof!)"
}
O shadowing oferece controle sobre qual comportamento é exposto, mantendo o acesso ao original por meio de qualificação explícita.
Desafio
FácilVamos criar um sistema de notificações em que diferentes canais de notificação possam personalizar a forma como formatam e entregam mensagens. Você usará o sombreamento de métodos para permitir que canais específicos substituam o comportamento padrão, ainda podendo acessar a implementação original quando necessário.
Você organizará seu código em três arquivos:
base.go: Crie uma structBaseNotificationcom os camposTitleePriority(ambos strings). Dê a ela um métodoFormat() stringque retorne a notificação em um formato padrão:[Priority] Title.channels.go: Crie dois tipos de canais de notificação que incorporemBaseNotificatione façam sombreamento do métodoFormatcom suas próprias implementações:EmailNotificationcom um campoRecipient. Seu métodoFormat()deve retornarEmail to [Recipient]: [Priority] TitleSlackNotificationcom um campoChannel. Seu métodoFormat()deve chamar o métodoBaseNotification.Format()incorporado e adicionar#[Channel]:ao início do resultado
main.go: Leia os detalhes da notificação da entrada, crie os dois tipos de notificações e demonstre o sombreamento imprimindo:- A saída formatada de
EmailNotification(usando seu método sombreado) - O formato base de
EmailNotification(chamando explicitamente o método incorporado) - A saída formatada de
SlackNotification(que usa internamente o método base)
- A saída formatada de
As seguintes entradas serão fornecidas:
- Linha 1: Título da notificação
- Linha 2: Nível de prioridade
- Linha 3: Destinatário do e-mail
- Linha 4: Nome do canal do Slack
Por exemplo, dadas as entradas Server Alert, HIGH, admin@company.com e ops-alerts, sua saída deverá ser:
Email to admin@company.com: HIGH Server Alert
[HIGH] Server Alert
#ops-alerts: [HIGH] Server AlertObserve como EmailNotification substitui completamente a formatação base, enquanto SlackNotification a aprimora chamando o método original e adicionando o contexto do canal. Ambas as abordagens demonstram diferentes formas de usar o sombreamento de métodos de maneira eficaz.
Experimente você mesmo
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
scanner := bufio.NewScanner(os.Stdin)
// Ler o título da notificação
scanner.Scan()
title := scanner.Text()
// Ler o nível de prioridade
scanner.Scan()
priority := scanner.Text()
// Ler o destinatário do email
scanner.Scan()
recipient := scanner.Text()
// Ler o nome do canal do Slack
scanner.Scan()
channel := scanner.Text()
// TODO: Crie um EmailNotification com a notificação base, title, priority e recipient
// TODO: Crie um SlackNotification com a notificação base, title, priority e channel
// TODO: Imprima a saída formatada do EmailNotification (usando seu método sombreado)
// TODO: Imprima o formato base do EmailNotification (chamando explicitamente o método embutido)
// TODO: Imprima a saída formatada do SlackNotification
fmt.Println() // Placeholder - remova ao implementar
}
Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.
Todas as lições de Programação Orientada a Objetos
1Fundamentos de OOP em Go
Arquivos ExternosWorkspace e Módulos do GoPacotes e ImportsNomes Exportados vs. Não ExportadosIntrodução à OOP em GoStructs como ClassesDefinindo Métodos em StructsReceptores de Ponteiro vs. de ValorInicialização de StructsFunções ConstrutorasRecapitulação — Calculadora Simples4Interfaces
Introdução às InterfacesImplementação ImplícitaInterface como ContratoInterface Vazia (any)Asserção de TipoSwitch de TipoComposição de InterfacesInterfaces Stringer e ErrorRecapitulação - Calculadora de Formas7Encapsulamento
Campos Exportados vs. Não ExportadosEncapsulamento no Nível de PacoteMétodos Getters e SettersOcultação de Informações em GoRecapitulação - Registros de Alunos10Genéricos (Go 1.18+)
Introdução aos genéricosParâmetros de tipoRestrições de tipoStructs genéricasAlternativa para métodos genéricosRecapitulação - Coleção genérica13Padrões de Projeto — Parte 1
Introdução aos Padrões de ProjetoPadrão SingletonPadrão FactoryPadrão Abstract FactoryPadrão ObserverPadrão Strategy2Tipos e Structs em Profundidade
Tipos Básicos e CompostosDefinições de Tipos PersonalizadosTags de StructStructs AnônimasStructs AninhadasValores Zero e PadrõesRecapitulação - Livro de Contatos5Composição em vez de herança
Por que Go não tem herançaNoções básicas de incorporação de structsPromoção de métodosIncorporação de várias structsIncorporação vs agregaçãoOcultação de métodos incorporadosRecapitulação - Hierarquia de funcionários8Tratamento de Erros e OOP
A interface errorTipos de Erro PersonalizadosEncapsulamento de Erros (fmt.Errorf)Erros Sentinelaerrors.Is() e errors.As()Panic, Defer e RecoverRecapitulação - Analisador de Arquivos3Ponteiros e Memória
Fundamentos de Ponteiros em GoPonteiros para StructsPassagem por Valor vs. ReferênciaA Função new()Coleta de Lixo em GoRecapitulação - Construtor de Lista Ligada6Polimorfismo em Go
Polimorfismo via InterfacesDuck Typing em GoRegras de Satisfação de InterfacesColeções PolimórficasInjeção de DependênciasRecapitulação - Processador de Pagamentos9Concorrência e OOP
Fundamentos de GoroutinesCanais e comunicaçãoCanais com e sem bufferInstrução selectsync.Mutex e sync.RWMutexsync.WaitGroupDesign de structs thread-safeRevisão - Worker PoolPratique por conta própria: Compilador de Go online