Menu
CoddyTech

Befehl-Muster

Teil des Abschnitts Objektorientierte Programmierung der GDScript-Journey von Coddy. Lektion 50 von 65.

Das Command-Muster verwandelt eine Aktion in ein Objekt. Das Objekt speichert alles, was zum Ausführen der Aktion benötigt wird, sodass du sie in einer Liste speichern, später ausführen oder rückgängig machen kannst.

Jeder Befehl hat dieselben zwei Methoden, die von einer abstrakten übergeordneten Klasse deklariert werden:

# command.gd
@abstract
class_name Command
extends RefCounted

@abstract func execute() -> void
@abstract func undo() -> void

Ein konkreter Befehl speichert das Objekt, auf das er angewendet wird, den sogenannten Empfänger, sowie die Daten der Aktion. Hier ist der Empfänger ein Hero mit einem 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 -= dx

Der Aufrufer führt Befehle aus und merkt sie sich. Er muss nie wissen, was ein Befehl bewirkt:

# 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
3

Der Verlauf ist ein Stapel: pop_back() nimmt den neuesten Befehl, sodass beim Rückgängigmachen die Aktionen in umgekehrter Reihenfolge durchlaufen werden. Dieselben Objekte ermöglichen dir auch eine Neubelegung der Tasten (eine Taste wird einem Befehl zugeordnet), Wiederholungen (die gespeicherte Liste wird erneut ausgeführt) und Zugwarteschlangen.

Referenzen verlaufen nur in eine Richtung: Die Befehle verweisen auf den Helden, und der Held weiß nichts von ihnen. Wenn der Held seine Befehle ebenfalls speichern würde, würden die Objekte sich gegenseitig am Leben erhalten und niemals freigegeben werden.

challenge icon

Aufgabe

Einfach

Eine Spielfigur bewegt sich auf einem Raster, und jeder Zug kann rückgängig gemacht werden. Command (command.gd) deklariert execute() und undo(), und Hero (hero.gd) hat x, y und position_text(). Schreibe:

  • MoveCommand: Der Konstruktor speichert die Spielfigur und die Schritte step_x und step_y. execute() addiert die Schritte zu x und y der Spielfigur, und undo() zieht sie ab.
  • CommandHistory: run(command) führt den Befehl aus und speichert ihn. undo_last() macht den zuletzt gespeicherten Befehl rückgängig, entfernt ihn und gibt true zurück; wenn nichts gespeichert ist, gibt die Methode false zurück.

Der bereitgestellte Code liest, wie viele Aktionen folgen, dann eine Aktion pro Zeile (up, down, left, right oder undo) und gibt nach jeder Aktion die Position aus. up verringert y um eins. Für right, up, undo, undo, undo lautet die Ausgabe:

right -> (1, 0)
up -> (1, -1)
undo -> (1, 0)
undo -> (0, 0)
Nothing to undo

Dein Code gehört in move_command.gd und command_history.gd. main.gd enthält den bereitgestellten Ein-/Ausgabecode und kann nicht bearbeitet werden.

Probier es selbst

extends Node

func _ready():
	# Vorgegebener Eingabe-/Ausgabecode: unverändert lassen
	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())
quiz iconTeste dich selbst

Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.

Alle Lektionen in Objektorientierte Programmierung

Übe selbstständig: Online-GDScript-Compiler