Pattern Command
Fa parte della sezione Programmazione orientata agli oggetti del percorso GDScript di Coddy. Lezione 50 di 65.
Il pattern Command trasforma un'azione in un oggetto. L'oggetto memorizza tutto ciò che serve per eseguire l'azione, così puoi conservarlo in un elenco, eseguirlo in seguito o annullarlo.
Ogni comando ha gli stessi due metodi, dichiarati da una classe genitore astratta:
# command.gd
@abstract
class_name Command
extends RefCounted
@abstract func execute() -> void
@abstract func undo() -> voidUn comando concreto mantiene l'oggetto su cui agisce, chiamato ricevitore, e i dati dell'azione. Qui il ricevitore è un Hero con un var x := 0:
# move_command.gd
class_name MoveCommand
extends Command
var hero: Hero
var dx: int
func _init(target: Hero, step: int) -> void:
hero = target
dx = step
func execute() -> void:
hero.x += dx
func undo() -> void:
hero.x -= dxL'invoker esegue i comandi e li ricorda. Non ha mai bisogno di sapere cosa fa un comando:
# command_history.gd
class_name CommandHistory
extends RefCounted
var done: Array[Command] = []
func run(command: Command) -> void:
command.execute()
done.append(command)
func undo_last() -> void:
if done.is_empty():
return
var last: Command = done.pop_back()
last.undo()# main.gd
var hero := Hero.new()
var history := CommandHistory.new()
history.run(MoveCommand.new(hero, 3))
history.run(MoveCommand.new(hero, 2))
print(hero.x)
history.undo_last()
print(hero.x)5
3La cronologia è uno stack: pop_back() prende il comando più recente, quindi annullare ripercorre le azioni in ordine inverso. Gli stessi oggetti ti permettono di rimappare i tasti (un tasto corrisponde a un comando), riprodurre le azioni (eseguire di nuovo l’elenco salvato) e gestire code di turni.
I riferimenti vanno in una sola direzione: i comandi puntano all'eroe, e l'eroe non sa nulla di loro. Se anche l'eroe memorizzasse i suoi comandi, gli oggetti si terrebbero in vita a vicenda e non verrebbero mai liberati.
Sfida
FacileUn eroe si muove su una griglia e ogni movimento può essere annullato. Command (command.gd) dichiara execute() e undo(), e Hero (hero.gd) ha x, y e position_text(). Scrivi:
MoveCommand: il costruttore memorizza l’eroe e i passistep_xestep_y.execute()aggiunge i passi axeydell’eroe, mentreundo()li sottrae.CommandHistory:run(command)esegue il comando e lo memorizza.undo_last()annulla il comando memorizzato più recente, lo rimuove e restituiscetrue; se non è stato memorizzato nulla, restituiscefalse.
Il codice fornito legge il numero di azioni successive, poi un’azione per riga (up, down, left, right o undo) e stampa la posizione dopo ognuna. up diminuisce y di uno. Per right, up, undo, undo, undo l’output è:
right -> (1, 0)
up -> (1, -1)
undo -> (1, 0)
undo -> (0, 0)
Nothing to undoIl tuo codice va in move_command.gd e command_history.gd. main.gd contiene il codice fornito per l’input/output e non può essere modificato.
Provalo tu
extends Node
func _ready():
# Codice di input/output fornito: lascialo così com'è
var hero := Hero.new()
var history := CommandHistory.new()
var steps := {"up": [0, -1], "down": [0, 1], "left": [-1, 0], "right": [1, 0]}
var count := int(OS.read_string_from_stdin())
for i in count:
var action := OS.read_string_from_stdin()
if action == "undo":
if history.undo_last():
print("undo -> ", hero.position_text())
else:
print("Nothing to undo")
else:
var step: Array = steps[action]
history.run(MoveCommand.new(hero, step[0], step[1]))
print(action, " -> ", hero.position_text())
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