Menu
CoddyTech

תבנית המצב

חלק מהיחידה תכנות מונחה עצמים במסלול ה-GDScript של Coddy. שיעור 54 מתוך 65.

תבנית State מעניקה לאובייקט אובייקט מצב נפרד עבור כל מצב שבו הוא יכול להיות. האובייקט מעביר את העבודה שלו למצב הנוכחי, ולכן ההתנהגות שלו משתנה כשהמצב משתנה.

עבור מספר קטן של מצבים, enum ו-match מספיקים. כשכל מצב מגיב לכמה פעולות בדרכו שלו, אותו match גדל עם כל מצב וכל פעולה. תבנית State מעבירה את הכללים של כל מצב למחלקה משלו:

# hero_state.gd
@abstract
class_name HeroState
extends RefCounted

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

handle() מחזירה את המצב הבא: אובייקט מצב חדש לעבור אליו, או self כדי להישאר.

# 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 נכתב באותו אופן: שמו הוא "Running", ו-"stop" מחזיר IdleState.new(). הגיבור, ההקשר, שומר את המצב הנוכחי ושואל אותו מה לעשות:

# 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

לאותה פעולה יש משמעויות שונות במצבים שונים: "stop" לא עושה דבר כשהדמות במצב המתנה, ועוצר גיבור שרץ. כל כלל נמצא במחלקה של המצב שלו, כך שמצב חדש, כמו קפיצה, הוא מחלקה חדשה אחת.

המצבים מחזירים את המצב הבא במקום לאחסן את הגיבור. מצב שמחזיק את הגיבור בזמן שהגיבור מחזיק את המצב היה יוצר מעגל הפניות, ואף אחד מהאובייקטים לא היה משתחרר לעולם.

challenge icon

אתגר

קל

דלת יכולה להיות Locked, Closed או Open. DoorState (door_state.gd) מצהירה על get_state_name() ועל handle(action), ו-LockedState (locked_state.gd) כבר כתובה: unlock מעביר את הדלת למצב Closed. כתבו:

  • ClosedState.handle(): הפעולה open מחזירה OpenState חדש, הפעולה lock מחזירה LockedState חדש, וכל פעולה אחרת מחזירה self.
  • OpenState.handle(): הפעולה close מחזירה ClosedState חדש, וכל פעולה אחרת מחזירה self.
  • Door.handle_action(action): מבקשת מהמצב הנוכחי את המצב הבא. אם זה אותו אובייקט, הדפיסו ACTION: still STATE; אחרת הדפיסו ACTION: OLD -> NEW ועברו למצב החדש.

הדלת מתחילה במצב Locked. הקוד שסופק קורא כמה פעולות יגיעו, ואז פעולה אחת בכל שורה, ומדפיס את המצב הסופי. עבור open, unlock, open, lock הפלט הוא:

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

הקוד שלכם נמצא בקבצים door.gd, closed_state.gd ו-open_state.gd. הקובץ main.gd מכיל את קוד הקלט/פלט שסופק ואי אפשר לערוך אותו.

נסו בעצמכם

extends Node

func _ready():
	# קוד הקלט/פלט שסופק: יש להשאיר אותו כפי שהוא
	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 iconבחנו את עצמכם

השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.

כל השיעורים ביחידה תכנות מונחה עצמים

תרגלו בעצמכם: קומפיילר GDScript אונליין