Duck Typing
Parte da seção Programação orientada a objetos do Journey de GDScript da Coddy. Lição 22 de 65.
Tipagem pato se importa com o que um objeto pode fazer, não a qual classe ele pertence. Se ele tiver o método que você chama, a chamada funciona. O nome vem do ditado "se nada como um pato e grasna como um pato, é um pato".
Essas duas classes não compartilham um pai próprio, mas ambas têm swim() e quack():
# duck.gd
class_name Duck
extends RefCounted
func swim() -> String:
return "Duck swimming"
func quack() -> String:
return "Quack!"# robot.gd
class_name Robot
extends RefCounted
func swim() -> String:
return "Robot swimming with propellers"
func quack() -> String:
return "Robot sound: BEEP BEEP!"Um parâmetro sem tipo aceita qualquer objeto. A função chama os métodos, e cada objeto executa os seus:
func make_it_swim_and_quack(thing) -> void:
print(thing.swim())
print(thing.quack())make_it_swim_and_quack(Duck.new())
make_it_swim_and_quack(Robot.new())Duck swimming
Quack!
Robot swimming with propellers
Robot sound: BEEP BEEP!A sobrescrita precisa de uma classe pai em comum; a tipagem estrutural não. Com o parâmetro tipado como thing: Duck, passar um Robot causaria um erro de análise.
Quando um objeto não possui o método, a chamada interrompe a função com um erro como Invalid call. Nonexistent function 'quack'. Primeiro, verifique com has_method(), que recebe o nome do método como uma String:
var things := [Duck.new(), Rock.new()]
for thing in things:
if thing.has_method("quack"):
print(thing.quack())
else:
print("This one cannot quack")Quack!
This one cannot quackO preço: com tipos, Godot encontra um nome de método incorreto antes de o programa ser executado; com tipagem dinâmica, você só descobre quando a linha é executada. Use-a para objetos de classes não relacionadas que compartilham alguns métodos.
Desafio
FácilUma explosão danifica tudo por perto que possa sofrer dano. Os objetos não compartilham uma classe pai. player.gd e rock.gd estão prontos: um Player tem take_damage(amount) e status(), enquanto um Rock só tem status().
- Em
crate.gd, dê aCrateuma variávelbrokenque começa comofalse, um métodotake_damage(amount)que quebra a caixa quando a quantidade é10ou mais, estatus()retornandoCrate: brokenouCrate: intact. - Em
explosion.gd, escreva o método estáticohit_all(things, amount). Ele chamatake_damage(amount)em cada objeto do Array que tenha esse método e retorna quantos objetos atingiu.
O código fornecido lê uma linha com nomes de objetos (player, crate ou rock), depois quantas explosões haverá e o dano de cada uma. Ele imprime quantos objetos cada explosão atingiu e, em seguida, o status de cada objeto. Para player crate rock e explosões de 5 e 20, ele imprime:
Explosion 1 hit 2 objects
Explosion 2 hit 2 objects
Player: 75 HP
Crate: broken
Rock: solidSeu código deve ficar em crate.gd e explosion.gd. main.gd contém o código fornecido de entrada/saída e não pode ser editado.
Experimente você mesmo
extends Node
func _ready():
# Código de entrada/saída fornecido: mantenha-o como está
var things := []
for word in OS.read_string_from_stdin().split(" "):
if word == "player":
things.append(Player.new())
elif word == "crate":
things.append(Crate.new())
else:
things.append(Rock.new())
var count := int(OS.read_string_from_stdin())
for i in count:
var hits := Explosion.hit_all(things, int(OS.read_string_from_stdin()))
print("Explosion %d hit %d objects" % [i + 1, hits])
for thing in things:
print(thing.status())
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 da POO
Arquivos externosIntrodução à POOClasses vs. objetosA palavra-chave selfMétodosPropriedadesConstrutor (_init)Revisão - Calculadora simples4Polimorfismo
Revisitando a Sobrescrita de MétodosDuck TypingClasses e Métodos AbstratosDesign de InterfacesRevisão - Calculadora de Formas7Sinais
O que é um sinal?Declarando e emitindoConectando-se a sinaisSinais com argumentosRevisão - Sistema de saúde10Padrões de Projeto Parte 2
Padrão CommandPadrão AdapterPadrão DecoratorPadrão Template MethodPadrão StatePadrão Composite2Propriedades de Classe
Variáveis de Instância vs. EstáticasFunções EstáticasMétodos Setters de PropriedadeMétodos Getters de PropriedadePrivado por ConvençãoRecapitulando: Gerenciador de Conta Bancária5Encapsulamento
Membros públicos e privadosValidação com settersOcultação de informaçõesPropriedades somente para leituraRevisão - Sistema de registros de alunos8Conceitos Avançados de POO
Composição vs. HerançaClasses InternasNós como ComponentesRefCounted vs. NodeEnums em Classes3Herança
Herança básicaA palavra-chave superSobrescrita de métodosCadeias de herançaVerificações de tipo com isRevisão - Hierarquia de funcionários6Métodos especiais
Introdução aos métodos virtuaisO método _to_stringIteradores personalizadosRevisão - Lista personalizada9Padrões de Projeto Parte 1
Introdução aos Padrões de ProjetoPadrão SingletonPadrão FactoryPadrão ObserverPadrão StrategyPratique por conta própria: Compilador de GDScript online