Promoção de métodos
Parte da seção Programação Orientada a Objetos do Journey de GO da Coddy. Lição 36 de 107.
Assim como a incorporação de structs promove os campos para a struct externa, o Go também promove métodos dos tipos incorporados. Isso significa que você pode chamar diretamente na struct externa os métodos definidos na struct incorporada.
type Engine struct {
Horsepower int
}
func (e Engine) Start() string {
return "Engine started"
}
type Car struct {
Model string
Engine // embutido
}
Como Car incorpora Engine, o método Start() é promovido automaticamente:
func main() {
c := Car{
Model: "Sedan",
Engine: Engine{Horsepower: 200},
}
fmt.Println(c.Start()) // Motor ligado
fmt.Println(c.Engine.Start()) // também funciona
}
Essa promoção tem uma consequência importante para as interfaces. Se o tipo incorporado satisfaz uma interface, o tipo externo também a satisfaz automaticamente:
type Starter interface {
Start() string
}
func Ignite(s Starter) {
fmt.Println(s.Start())
}
func main() {
c := Car{Model: "Sedan", Engine: Engine{Horsepower: 200}}
Ignite(c) // Car satisfaz Starter através de Engine
}
O tipo Car nunca implementa explicitamente Starter, mas satisfaz a interface porque seu Engine incorporado tem o método necessário. É assim que Go alcança a reutilização de comportamento sem a herança tradicional.
Desafio
FácilVamos criar um sistema de reprodução de música que demonstra como os métodos de tipos incorporados são promovidos para o tipo externo e como isso permite a satisfação de interfaces por meio de composição.
Você organizará seu código em dois arquivos:
audio.go: crie os componentes básicos do seu reprodutor de música:- Uma struct
AudioPlayercom um campoBrand(string) e um métodoPlay() stringque retorna[Brand] playing audio - Uma interface
Playableque exige um métodoPlay() string - Uma struct
Smartphonecom um campoModelque incorporaAudioPlayer - Uma struct
Tabletcom um campoModelque incorporaAudioPlayer
- Uma struct
main.go: crie uma função chamadaStartPlaybackque aceite qualquerPlayablee retorne o resultado da chamada dePlay(). Leia as informações dos dispositivos da entrada, crie um Smartphone e um Tablet e demonstre que ambos satisfazem a interfacePlayablepor meio doAudioPlayerincorporado, embora nenhum dos dois tipos implemente explicitamentePlay().
As seguintes entradas serão fornecidas:
- Linha 1: nome do modelo do Smartphone
- Linha 2: marca de áudio do Smartphone
- Linha 3: nome do modelo do Tablet
- Linha 4: marca de áudio do Tablet
Para cada dispositivo, imprima seu modelo seguido do resultado de passá-lo para StartPlayback.
Por exemplo, dadas as entradas iPhone 15, Apple Audio, iPad Pro e Beats, sua saída deverá ser:
iPhone 15
Apple Audio playing audio
iPad Pro
Beats playing audioObserve como tanto Smartphone quanto Tablet podem ser passados para StartPlayback, porque o método Play() de AudioPlayer é automaticamente promovido para cada tipo externo, satisfazendo a interface Playable sem nenhum código adicional.
Experimente você mesmo
package main
import (
"bufio"
"fmt"
"os"
)
// TODO: Crie uma função StartPlayback que aceita qualquer Playable
// e retorna o resultado de chamar Play()
func main() {
scanner := bufio.NewScanner(os.Stdin)
// Ler o modelo do smartphone
scanner.Scan()
smartphoneModel := scanner.Text()
// Ler a marca de áudio do smartphone
scanner.Scan()
smartphoneBrand := scanner.Text()
// Ler o modelo do tablet
scanner.Scan()
tabletModel := scanner.Text()
// Ler a marca de áudio do tablet
scanner.Scan()
tabletBrand := scanner.Text()
// TODO: Crie um Smartphone com o AudioPlayer embutido
// TODO: Crie um Tablet com o AudioPlayer embutido
// TODO: Imprima o modelo do smartphone, depois chame StartPlayback com o smartphone
// TODO: Imprima o modelo do tablet, depois chame StartPlayback com o tablet
_ = smartphoneModel
_ = smartphoneBrand
_ = tabletModel
_ = tabletBrand
fmt.Println("TODO: Complete the implementation")
}
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