Menu
CoddyTech
flag Ar iconالعربيةdown icon

نمط الحالة

جزء من قسم البرمجة كائنية التوجّه في رحلة GDScript على Coddy. الدرس 54 من 65.

يمنح نمط State الكائن كائن حالة منفصلًا لكل وضع يمكن أن يكون فيه. يُسند الكائن عمله إلى الحالة الحالية، لذلك يتغير سلوكه عندما تتغير الحالة.

عند وجود بضع حالات، يكون التعداد وmatch كافيين. عندما تتفاعل كل حالة مع عدة إجراءات بطريقتها الخاصة، ينمو match مع كل حالة وكل إجراء. ينقل نمط الحالة قواعد كل حالة إلى صنفها الخاص:

# 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 عبر الإنترنت