Menu
CoddyTech

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 vole

Ici, 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.

challenge icon

Défi

Facile

Un chevalier n’hérite pas d’une arme : un chevalier a une arme et peut en changer. Construis les deux classes.

  • Weapon stocke weapon_name et damage, tous deux définis par le constructeur : Weapon.new("Sword", 7).
  • Knight stocke knight_name (fourni par le constructeur) et une arme, qui vaut null au départ.
  • equip(new_weapon) remplace l’arme et drop() la remet à null.
  • attack() renvoie Ada attacks with Sword for 7 damage, en utilisant le nom du chevalier ainsi que le nom et les dégâts de l’arme, ou Ada has no weapon s’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 weapon

Ton 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())
quiz iconTestez-vous

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

Entraînez-vous par vous-même : Compilateur GDScript en ligne