Composition ou héritage
Fait partie de la section Programmation orientée objet du Journey GDScript de Coddy. Leçon 40 sur 65.
Les classes réutilisent le code de deux façons. L’héritage (extends) indique qu’une classe est une sorte d’une autre classe : un Mage est un Player. La composition indique qu’une classe possède une partie : elle stocke un autre objet dans une variable membre et lui délègue le travail :
# motor.gd
class_name Motor
extends RefCounted
func start() -> String:
return "motor running"
# car.gd
class_name Car
extends RefCounted
var motor := Motor.new()
func start() -> String:
return "Car starts, " + motor.start()Car.new().start() renvoie Car starts, motor running. La voiture ne sait pas comment fonctionne un moteur : elle appelle motor.start(). Confier un appel à une partie de cette façon s’appelle la délégation. (La classe s’appelle Motor parce que Engine est déjà une classe Godot.)
La composition est utile lorsque les parties changent ou se combinent. Avec l’héritage, un personnage qui marche et un personnage qui vole sont deux sous-classes, et une chauve-souris qui commence à voler ne peut pas changer de classe. Avec la composition, le personnage possède une partie qui gère son déplacement, et la remplacer ne nécessite qu’une affectation :
# character.gd
class_name Character
extends RefCounted
var char_name: String
var movement: Movement
func _init(new_name: String, new_movement: Movement) -> void:
char_name = new_name
movement = new_movement
func move() -> String:
return char_name + " " + movement.move()
# main.gd
var bat := Character.new("Bat", Walk.new())
print(bat.move()) # Bat marche
bat.movement = Fly.new()
print(bat.move()) # Bat voleIci, Walk et Fly étendent une petite classe Movement : les deux techniques fonctionnent ensemble. Une classe GDScript ne peut extend qu’une seule classe ; la composition est donc aussi un moyen pour un objet d’acquérir plusieurs capacités, en contenant plusieurs éléments.
Utilise l’héritage pour une véritable relation « est un » qui ne change jamais. Utilise la composition lorsque la classe « possède » quelque chose, ou lorsque la partie doit pouvoir être remplacée pendant le déroulement du jeu.
Défi
FacileUn chevalier n’hérite pas d’une arme : un chevalier a une arme et peut en changer. Construis les deux classes.
Weaponstockeweapon_nameetdamage, tous deux définis par le constructeur :Weapon.new("Sword", 7).Knightstockeknight_name(fourni par le constructeur) et une arme, qui vautnullau départ.equip(new_weapon)remplace l’arme etdrop()la remet ànull.attack()renvoieAda attacks with Sword for 7 damage, en utilisant le nom du chevalier ainsi que le nom et les dégâts de l’arme, ouAda has no weapons’il n’y en a pas.
Le code fourni lit le nom du chevalier et le nombre de commandes qui suivent (equip Sword 7, drop, attack), puis les exécute. Pour Ada et attack, equip Sword 7, attack, equip Axe 12, attack, drop, attack, il affiche :
Ada has no weapon
Equipped Sword
Ada attacks with Sword for 7 damage
Equipped Axe
Ada attacks with Axe for 12 damage
Dropped the weapon
Ada has no weaponTon code doit se trouver dans weapon.gd et knight.gd. main.gd contient le code fourni pour les entrées/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 knight := Knight.new(OS.read_string_from_stdin())
var count := int(OS.read_string_from_stdin())
for i in count:
var parts := OS.read_string_from_stdin().split(" ")
if parts[0] == "equip":
knight.equip(Weapon.new(parts[1], int(parts[2])))
print("Equipped ", parts[1])
elif parts[0] == "drop":
knight.drop()
print("Dropped the weapon")
else:
print(knight.attack())
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