Tipado pato
Parte de la sección Programación orientada a objetos del Journey de GDScript de Coddy. Lección 22 de 65.
La tipificación pato se centra en lo que un objeto puede hacer, no en la clase a la que pertenece. Si tiene el método que llamas, la llamada funciona. El nombre proviene del dicho «si nada como un pato y grazna como un pato, es un pato».
Estas dos clases no comparten ningún padre propio, pero ambas tienen swim() y 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!"Un parámetro sin tipo acepta cualquier objeto. La función llama a los métodos, y cada objeto ejecuta los suyos:
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!La sobrescritura necesita una clase padre compartida; la tipificación pato no. Con el parámetro tipado como thing: Duck, pasar un Robot sería un error de análisis.
Cuando a un objeto le falta el método, la llamada detiene la función con un error como Invalid call. Nonexistent function 'quack'. Primero, comprueba con has_method(), que recibe el nombre del método como un 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 quackEl precio: con los tipos, Godot detecta un nombre de método incorrecto antes de que se ejecute el programa; con el tipado pato, solo te enteras cuando se ejecuta la línea. Úsalo para objetos de clases no relacionadas que comparten algunos métodos.
Desafío
FácilUna explosión daña todo lo que hay cerca y que puede recibir daño. Los objetos no comparten ninguna clase principal. player.gd y rock.gd están terminados: un Player tiene take_damage(amount) y status(), mientras que un Rock solo tiene status().
- En
crate.gd, dale aCrateuna variablebrokenque empiece enfalse, un métodotake_damage(amount)que rompa la caja cuando la cantidad sea10o más, y un métodostatus()que devuelvaCrate: brokenoCrate: intact. - En
explosion.gd, escribe la función estáticahit_all(things, amount). Llama atake_damage(amount)en cada objeto del Array que tenga ese método y devuelve cuántos objetos alcanzó.
El código proporcionado lee una línea con nombres de objetos (player, crate o rock), después cuántas explosiones siguen y el daño de cada una. Imprime cuántos objetos alcanzó cada explosión y, después, el estado de cada objeto. Para player crate rock y explosiones de 5 y 20, imprime:
Explosion 1 hit 2 objects
Explosion 2 hit 2 objects
Player: 75 HP
Crate: broken
Rock: solidTu código va en crate.gd y explosion.gd. main.gd contiene el código de entrada/salida proporcionado y no se puede editar.
Pruébalo tú mismo
extends Node
func _ready():
# Código de entrada/salida proporcionado: mantenlo tal 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 lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.
Todas las lecciones de Programación orientada a objetos
1Fundamentos de la programación orientada a objetos
Archivos externosIntroducción a la programación orientada a objetosClases vs. objetosLa palabra clave selfMétodosPropiedadesConstructor (_init)Repaso: calculadora sencilla4Polimorfismo
Repaso de la sobrescritura de métodosTipado patoClases y métodos abstractosDiseño de interfacesRepaso: calculadora de formas7Señales
¿Qué es una señal?Declarar y emitirConectarse a las señalesSeñales con argumentosRepaso: sistema de salud10Patrones de diseño, parte 2
Patrón CommandPatrón AdapterPatrón DecoratorPatrón Template MethodPatrón StatePatrón Composite2Propiedades de clase
Variables de instancia y estáticasFunciones estáticasMétodos setter de propiedadesMétodos getter de propiedadesPrivado por convenciónRepaso: administrador de cuentas bancarias5Encapsulación
Miembros públicos y privadosValidación con settersOcultación de informaciónPropiedades de solo lecturaRepaso: sistema de registros de estudiantes8Conceptos avanzados de POO
Composición frente a herenciaClases internasNodos como componentesRefCounted frente a NodeEnums en clases3Herencia
Herencia básicaLa palabra clave superSobrescritura de métodosCadenas de herenciaComprobaciones de tipo con isRepaso: jerarquía de empleados6Métodos especiales
Introducción a los métodos virtualesEl método _to_stringIteradores personalizadosRepaso: lista personalizada9Patrones de diseño, parte 1
Introducción a los patrones de diseñoPatrón SingletonPatrón FactoryPatrón ObserverPatrón StrategyPractica por tu cuenta: Compilador de GDScript online