Duck typing
Fa parte della sezione Programmazione orientata agli oggetti del percorso GDScript di Coddy. Lezione 22 di 65.
Il duck typing riguarda ciò che un oggetto può fare, non la classe a cui appartiene. Se ha il metodo che chiami, la chiamata funziona. Il nome deriva dal detto «se nuota come un'anatra e fa qua qua come un'anatra, allora è un'anatra».
Queste due classi non condividono alcuna classe genitore, ma entrambe hanno swim() e 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 parametro senza tipo accetta qualsiasi oggetto. La funzione chiama i metodi e ogni oggetto esegue i propri:
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!Per eseguire l'override serve una classe genitore condivisa; il duck typing non ne ha bisogno. Con il parametro tipizzato thing: Duck, passare un Robot causerebbe un errore di analisi.
Quando a un oggetto manca il metodo, la chiamata interrompe la funzione con un errore come Invalid call. Nonexistent function 'quack'. Prima verifica con has_method(), che accetta il nome del metodo come 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 quackIl prezzo: con i tipi, Godot individua il nome di un metodo errato prima che il programma venga eseguito; con il duck typing lo scopri solo quando viene eseguita la riga. Usalo per oggetti di classi non correlate che condividono alcuni metodi.
Sfida
FacileUn'esplosione danneggia tutto ciò che si trova nelle vicinanze e può subire danni. Gli oggetti non condividono alcuna classe genitore. player.gd e rock.gd sono già pronti: un Player ha take_damage(amount) e status(), mentre un Rock ha solo status().
- In
crate.gd, assegna aCrateuna variabilebrokenche inizialmente valefalse, un metodotake_damage(amount)che rompe la cassa quando la quantità è pari o superiore a10estatus()che restituisceCrate: brokenoppureCrate: intact. - In
explosion.gd, scrivi la funzione staticahit_all(things, amount). Chiamatake_damage(amount)su ogni oggetto dell'Array che ha quel metodo e restituisce quanti oggetti ha colpito.
Il codice fornito legge una riga con i nomi degli oggetti (player, crate o rock), poi il numero di esplosioni e i danni di ciascuna. Stampa quanti oggetti ha colpito ogni esplosione, poi lo stato di ogni oggetto. Per player crate rock e le esplosioni con danni pari a 5 e 20, stampa:
Explosion 1 hit 2 objects
Explosion 2 hit 2 objects
Player: 75 HP
Crate: broken
Rock: solidIl tuo codice va in crate.gd e explosion.gd. main.gd contiene il codice fornito per input/output e non può essere modificato.
Provalo tu
extends Node
func _ready():
# Codice di input/output fornito: lascialo così com'è
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())
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