Composizione vs ereditarietà
Fa parte della sezione Programmazione orientata agli oggetti del percorso GDScript di Coddy. Lezione 40 di 65.
Le classi riutilizzano il codice in due modi. L'ereditarietà (extends) indica che una classe è un tipo di un'altra classe: un Mage è un Player. La composizione indica che una classe ha una parte: memorizza un altro oggetto in una variabile membro e gli delega il lavoro:
# 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() restituisce Car starts, motor running. L'auto non sa come funziona un motore: chiama motor.start(). Affidare una chiamata a una parte in questo modo si chiama delegazione. (La classe si chiama Motor perché Engine è già una classe di Godot.)
La composizione ripaga quando le parti cambiano o si combinano. Con l'ereditarietà, un personaggio che cammina e un personaggio che vola sono due sottoclassi, e un pipistrello che inizia a volare non può cambiare classe. Con la composizione, il personaggio ha una parte dedicata al movimento, e sostituirla richiede una sola assegnazione:
# 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 walks
bat.movement = Fly.new()
print(bat.move()) # Bat fliesQui Walk e Fly estendono una piccola classe Movement: le due tecniche funzionano insieme. Una classe GDScript può extend una sola classe, quindi la composizione è anche il modo in cui un oggetto acquisisce diverse abilità, contenendo diverse parti.
Usa l'ereditarietà per una relazione «è un» reale che non cambia mai. Usa la composizione quando la classe «ha» qualcosa o quando la parte deve essere sostituita mentre il gioco è in esecuzione.
Sfida
FacileUn cavaliere non eredita da un'arma: un cavaliere ha un'arma e può cambiarla. Crea entrambe le classi.
Weaponmemorizzaweapon_nameedamage, entrambi impostati dal costruttore:Weapon.new("Sword", 7).Knightmemorizzaknight_name(dal costruttore) e un'arma, che all'inizio ènull.equip(new_weapon)sostituisce l'arma edrop()la reimposta anull.attack()restituisceAda attacks with Sword for 7 damage, usando il nome del cavaliere e il nome e i danni dell'arma, oppureAda has no weaponquando non ce n'è una.
Il codice fornito legge il nome del cavaliere e il numero di comandi che seguono (equip Sword 7, drop, attack) e li esegue. Per Ada e attack, equip Sword 7, attack, equip Axe 12, attack, drop, attack stampa:
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 weaponIl tuo codice va in weapon.gd e knight.gd. main.gd contiene il codice di input/output fornito e non può essere modificato.
Provalo tu
extends Node
func _ready():
# Supplied input/output code: keep it as it is
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())
Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.
Tutte le lezioni di Programmazione orientata agli oggetti
1Fondamenti della programmazione orientata agli oggetti
File esterniIntroduzione alla programmazione orientata agli oggettiClassi e oggetti a confrontoLa parola chiave selfMetodiProprietàCostruttore (_init)Riepilogo - Calcolatrice semplice4Polimorfismo
Ripasso dell'override dei metodiDuck typingClassi e metodi astrattiProgettazione delle interfacceRiepilogo - Calcolatore di forme7Segnali
Che cos'è un segnale?Dichiarare ed emettereCollegarsi ai segnaliSegnali con argomentiRipasso - Sistema della salute10Pattern di progettazione, parte 2
Pattern CommandPattern AdapterPattern DecoratorPattern Template MethodPattern StatePattern Composite2Proprietà delle classi
Variabili di istanza e staticheFunzioni staticheSetter delle proprietàGetter delle proprietàPrivato per convenzioneRiepilogo - Gestore di conti bancari5Incapsulamento
Membri pubblici e privatiValidazione con i setterNascondimento delle informazioniProprietà di sola letturaRiepilogo - Sistema di gestione dei dati degli studenti8Concetti avanzati di OOP
Composizione vs ereditarietàClassi interneNodi come componentiRefCounted vs NodeEnum nelle classi11Progetto: Gestione della biblioteca
Panoramica del progettoClassi Libro e Utente3Ereditarietà
Ereditarietà di baseLa parola chiave superOverride dei metodiCatene di ereditarietàControlli di tipo con isRipasso - Gerarchia dei dipendenti6Metodi speciali
Introduzione ai metodi virtualiIl metodo _to_stringIteratori personalizzatiRiepilogo - Lista personalizzata9Modelli di progettazione, parte 1
Introduzione ai modelli di progettazionePattern SingletonPattern FactoryPattern ObserverPattern StrategyEsercitati da solo: Compilatore GDScript online