Menu
CoddyTech

Mẫu trạng thái

Thuộc phần Lập trình hướng đối tượng trong hành trình GDScript của Coddy. Bài học 54 trên 65.

Mẫu State cung cấp cho một đối tượng một đối tượng trạng thái riêng cho mỗi chế độ mà nó có thể ở trong đó. Đối tượng giao phần việc của mình cho trạng thái hiện tại, vì vậy hành vi của nó thay đổi khi trạng thái thay đổi.

Với một vài trạng thái, enum và match là đủ. Khi mỗi trạng thái phản ứng với nhiều hành động theo cách riêng, match sẽ dài thêm với mỗi trạng thái và mỗi hành động. Mẫu State chuyển các quy tắc của từng trạng thái vào lớp riêng:

# hero_state.gd
@abstract
class_name HeroState
extends RefCounted

@abstract func get_state_name() -> String
@abstract func handle(action: String) -> HeroState

handle() trả về trạng thái tiếp theo: một đối tượng trạng thái mới để chuyển sang, hoặc self để giữ nguyên.

# idle_state.gd
class_name IdleState
extends HeroState

func get_state_name() -> String:
	return "Idle"

func handle(action: String) -> HeroState:
	if action == "run":
		return RunState.new()
	return self

RunState cũng được viết tương tự: tên của nó là "Running", và "stop" trả về IdleState.new(). Người hùng, tức ngữ cảnh, giữ trạng thái hiện tại và hỏi trạng thái đó cần làm gì:

# hero.gd
class_name Hero
extends RefCounted

var state: HeroState = IdleState.new()

func handle_action(action: String) -> void:
	var next := state.handle(action)
	if next != state:
		print(state.get_state_name(), " -> ", next.get_state_name())
		state = next
# main.gd
var hero := Hero.new()
for action in ["stop", "run", "run", "stop"]:
	hero.handle_action(action)
Idle -> Running
Running -> Idle

Cùng một hành động có ý nghĩa khác nhau ở các trạng thái khác nhau: "stop" không làm gì khi đang ở trạng thái chờ và dừng anh hùng đang chạy. Mỗi quy tắc nằm trong lớp của trạng thái tương ứng, vì vậy một trạng thái mới như nhảy sẽ cần một lớp mới.

Các trạng thái trả về trạng thái tiếp theo thay vì lưu nhân vật chính. Nếu một trạng thái giữ nhân vật chính và nhân vật chính giữ trạng thái đó, sẽ tạo thành một vòng tham chiếu, khiến cả hai đối tượng không bao giờ được giải phóng.

challenge icon

Thử thách

Dễ

Cửa ở trạng thái Locked, Closed hoặc Open. DoorState (door_state.gd) khai báo get_state_name() và handle(action), còn LockedState (locked_state.gd) đã được viết: unlock đưa cửa về trạng thái Closed. Hãy viết:

  • ClosedState.handle(): open trả về một OpenState mới, lock trả về một LockedState mới, trường hợp khác trả về self.
  • OpenState.handle(): close trả về một ClosedState mới, trường hợp khác trả về self.
  • Door.handle_action(action): yêu cầu trạng thái hiện tại cho biết trạng thái tiếp theo. Nếu đó là cùng một đối tượng, hãy in ra ACTION: still STATE; nếu không, hãy in ra ACTION: OLD -> NEW rồi chuyển sang trạng thái mới.

Cửa bắt đầu ở trạng thái Locked. Code được cung cấp đọc số lượng hành động tiếp theo, rồi đọc từng hành động trên một dòng và in ra trạng thái cuối cùng. Với open, unlock, open, lock, đầu ra là:

open: still Locked
unlock: Locked -> Closed
open: Closed -> Open
lock: still Open
Final state: Open

Code của bạn nằm trong door.gd, closed_state.gd và open_state.gd. main.gd chứa code đầu vào/đầu ra được cung cấp và không thể chỉnh sửa.

Tự làm thử

extends Node

func _ready():
	# Đoạn code đầu vào/đầu ra đã cho: giữ nguyên
	var door := Door.new()
	var count := int(OS.read_string_from_stdin())
	for i in count:
		door.handle_action(OS.read_string_from_stdin())
	print("Final state: ", door.state.get_state_name())
quiz iconTự kiểm tra

Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.

Tất cả bài học trong Lập trình hướng đối tượng

Tự luyện tập: Trình biên dịch GDScript online