Typage canard
Fait partie de la section Programmation orientée objet du Journey GDScript de Coddy. Leçon 22 sur 65.
Le typage canard s’intéresse à ce qu’un objet peut faire, et non à la classe à laquelle il appartient. S’il possède la méthode que vous appelez, l’appel fonctionne. Le nom vient du dicton « s’il nage comme un canard et cancane comme un canard, c’est un canard ».
Ces deux classes n’ont pas de parent commun, mais elles possèdent toutes deux swim() et 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 paramètre sans type accepte n’importe quel objet. La fonction appelle les méthodes, et chaque objet exécute les siennes :
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 redéfinition nécessite une classe parent commune ; le typage canard, non. Avec le paramètre typé thing: Duck, passer un Robot provoquerait une erreur d’analyse.
Lorsqu’un objet ne possède pas la méthode, l’appel interrompt la fonction avec une erreur telle que Invalid call. Nonexistent function 'quack'. Vérifie d’abord avec has_method(), qui prend le nom de la méthode sous forme de 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 quackLe prix à payer : avec les types, Godot détecte un nom de méthode incorrect avant l’exécution du programme ; avec le typage canard, tu ne le découvres que lorsque la ligne s’exécute. Utilise-le pour des objets de classes sans lien entre elles qui partagent quelques méthodes.
Défi
FacileUne explosion endommage tout ce qui se trouve à proximité et peut subir des dégâts. Les objets n’ont aucune classe parente commune. player.gd et rock.gd sont terminés : un Player possède take_damage(amount) et status(), un Rock ne possède que status().
- Dans
crate.gd, donnez àCrateune variablebrokenqui vaut initialementfalse, une méthodetake_damage(amount)qui casse la caisse lorsque la quantité de dégâts est égale ou supérieure à10, et une méthodestatus()qui renvoieCrate: brokenouCrate: intact. - Dans
explosion.gd, écrivez la méthode statiquehit_all(things, amount). Elle appelletake_damage(amount)sur chaque objet du tableau Array qui possède cette méthode, puis renvoie le nombre d’objets touchés.
Le code fourni lit une ligne de noms d’objets (player, crate ou rock), puis le nombre d’explosions qui suivent et les dégâts infligés par chacune. Il affiche le nombre d’objets touchés par chaque explosion, puis le statut de chaque objet. Pour player crate rock et des explosions de 5 et 20, il affiche :
Explosion 1 hit 2 objects
Explosion 2 hit 2 objects
Player: 75 HP
Crate: broken
Rock: solidVotre code va dans crate.gd et explosion.gd. main.gd contient le code fourni pour les entrées et sorties et ne peut pas être modifié.
Essayez vous-même
extends Node
func _ready():
# Code d'entrée/sortie fourni : conservez-le tel quel
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())
Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.
Toutes les leçons de Programmation orientée objet
1Fondamentaux de la POO
Fichiers externesIntroduction à la POOClasses et objetsLe mot-clé selfMéthodesPropriétésConstructeur (_init)Récapitulatif - Calculatrice simple4Polymorphisme
Retour sur la redéfinition des méthodesTypage canardClasses et méthodes abstraitesConception d’interfacesRécapitulatif – Calculateur de formes7Signaux
Qu’est-ce qu’un signal ?Déclarer et émettreSe connecter aux signauxSignaux avec argumentsRécapitulatif - système de santé10Patrons de conception, partie 2
Patron CommandePatron AdaptateurPatron DécorateurPatron Méthode modèlePatron ÉtatPatron Composite2Propriétés de classe
Variables d’instance et variables statiquesFonctions statiquesSetters de propriétésGetters de propriétésPrivé par conventionRécapitulatif - Gestionnaire de comptes bancaires5Encapsulation
Membres publics et privésValidation avec les méthodes setterMasquage de l’informationPropriétés en lecture seuleRécapitulatif - Système de dossiers étudiants8Concepts avancés de la POO
Composition ou héritageClasses internesLes nœuds comme composantsRefCounted ou NodeEnums dans les classes3Héritage
Héritage de baseLe mot-clé superRedéfinition de méthodesChaînes d’héritageVérifier les types avec isRécapitulatif – Hiérarchie des employés6Méthodes spéciales
Introduction aux méthodes virtuellesLa méthode _to_stringItérateurs personnalisésRécapitulatif – Liste personnalisée9Patrons de conception, partie 1
Introduction aux patrons de conceptionPatron SingletonPatron FactoryPatron ObserverPatron StrategyEntraînez-vous par vous-même : Compilateur GDScript en ligne