תבנית הפקודה
חלק מהיחידה תכנות מונחה עצמים במסלול ה-GDScript של Coddy. שיעור 50 מתוך 65.
תבנית Command הופכת פעולה לאובייקט. האובייקט שומר את כל מה שנדרש כדי לבצע את הפעולה, כך שאפשר לשמור אותו ברשימה, לבצע אותו מאוחר יותר או לבטל אותו.
לכל פקודה יש אותן שתי מתודות, המוצהרות במחלקת אב מופשטת:
# command.gd
@abstract
class_name Command
extends RefCounted
@abstract func execute() -> void
@abstract func undo() -> voidפקודה קונקרטית שומרת את האובייקט שעליו היא פועלת, שנקרא המקבל, ואת נתוני הפעולה. כאן המקבל הוא Hero עם 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המפעיל מריץ פקודות וזוכר אותן. הוא לעולם לא צריך לדעת מה פקודה עושה:
# 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() שולפת את הפקודה החדשה ביותר, כך שביטול הפעולות עובר עליהן לאחור, בסדר הפוך. אותם אובייקטים מאפשרים לך גם למפות מחדש מקשים (מקש משויך לפקודה), להפעיל שוב רצפי פעולות (להריץ שוב את הרשימה השמורה) ולנהל תורים של תורות.
ההפניות הן חד־כיווניות: הפקודות מצביעות על הגיבור, והגיבור לא יודע עליהן דבר. אם הגיבור היה שומר גם את הפקודות שלו, האובייקטים היו מחזיקים זה את זה בחיים ולא היו משתחררים לעולם.
אתגר
קלגיבור נע על גבי רשת, וניתן לבטל כל תנועה. 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 באחד. עבור 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())
השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.
כל השיעורים ביחידה תכנות מונחה עצמים
1יסודות התכנות מונחה העצמים
קבצים חיצונייםמבוא ל-OOPמחלקות לעומת אובייקטיםמילת המפתח selfמתודותמאפייניםבנאי (_init)חזרה – מחשבון פשוט2מאפייני מחלקה
משתני מופע לעומת משתנים סטטייםפונקציות סטטיותקובעי מאפייניםמאחזרי מאפייניםפרטיים לפי מוסכמהסיכום – מנהל חשבון בנק5כימוס
איברים ציבוריים ופרטייםאימות באמצעות Settersהסתרת מידעמאפיינים לקריאה בלבדסיכום – מערכת לניהול רשומות תלמידיםתרגלו בעצמכם: קומפיילר GDScript אונליין