Menu
CoddyTech

커맨드 패턴

Coddy GDScript 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨. 65개 중 50번째.

Command 패턴은 동작을 객체로 만듭니다. 객체에는 동작을 실행하는 데 필요한 모든 것이 저장되므로, 목록에 보관하거나 나중에 실행하거나 실행을 취소할 수 있습니다.

모든 명령에는 추상 부모 클래스에서 선언된 동일한 두 메서드가 있습니다.

# command.gd
@abstract
class_name Command
extends RefCounted

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

구체 명령은 수신자라고 하는, 해당 명령이 동작하는 객체와 동작의 데이터를 보관합니다. 여기서 수신자는 var x := 0을 가진 Hero입니다:

# 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

호출자는 명령을 실행하고 기억합니다. 명령이 무엇을 하는지는 알 필요가 없습니다:

# 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

기록은 스택입니다. pop_back()은 가장 최근 명령을 가져오므로 실행 취소를 하면 작업을 역순으로 되돌아갑니다. 같은 객체를 사용하면 키 재매핑(키를 명령에 연결), 재생(저장된 목록을 다시 실행), 턴 대기열도 구현할 수 있습니다.

참조는 한 방향으로만 이어집니다. 명령이 영웅을 가리키며, 영웅은 명령에 대해 아무것도 모릅니다. 영웅도 명령을 저장한다면 객체들이 서로를 계속 유지해 메모리에서 해제되지 않을 것입니다.

challenge icon

챌린지

쉬움

영웅은 격자에서 이동하며, 모든 이동을 되돌릴 수 있습니다. Command(command.gd)는 execute()와 undo()를 선언하고, Hero(hero.gd)에는 x, y와 position_text()가 있습니다. 다음을 작성하세요.

  • MoveCommand: 생성자는 영웅과 이동량 step_x, step_y를 저장합니다. execute()는 이동량을 영웅의 x와 y에 더하고, undo()는 이동량을 뺍니다.
  • CommandHistory: run(command)는 명령을 실행하고 저장합니다. undo_last()는 가장 최근에 저장한 명령을 실행 취소하고 제거한 다음 true를 반환합니다. 저장된 명령이 없으면 false를 반환합니다.

제공된 코드는 이어지는 동작의 수를 읽은 다음, 한 줄에 하나씩 동작(up, down, left, right 또는 undo)을 읽고 매 동작 후 위치를 출력합니다. up은 y를 1만큼 낮춥니다. right, up, undo, undo, undo를 입력했을 때 출력은 다음과 같습니다.

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

코드는 move_command.gd와 command_history.gd에 작성하세요. main.gd에는 제공된 입력/출력 코드가 있으며 수정할 수 없습니다.

직접 해보기

extends Node

func _ready():
	# 제공된 입출력 코드: 그대로 유지하세요
	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 icon실력 점검

이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.

객체 지향 프로그래밍의 모든 레슨

직접 연습해 보세요: 온라인 GDScript 컴파일러