Menu
CoddyTech

קומפוזיציה לעומת ירושה

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

מחלקות משתמשות מחדש בקוד בשתי דרכים. ירושה (extends) פירושה שמחלקה היא סוג של מחלקה אחרת: Mage היא Player. הרכבה פירושה שלמחלקה יש רכיב: היא מאחסנת אובייקט אחר במשתנה חבר ומעבירה אליו את העבודה:

# motor.gd
class_name Motor
extends RefCounted

func start() -> String:
	return "motor running"

# car.gd
class_name Car
extends RefCounted

var motor := Motor.new()

func start() -> String:
	return "Car starts, " + motor.start()

Car.new().start() מחזיר Car starts, motor running. המכונית לא יודעת איך מנוע עובד: היא קוראת ל־motor.start(). העברת קריאה לחלק בצורה כזאת נקראת האצלה. (שם המחלקה הוא Motor כי Engine היא כבר מחלקה של Godot.)

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

# character.gd
class_name Character
extends RefCounted

var char_name: String
var movement: Movement

func _init(new_name: String, new_movement: Movement) -> void:
	char_name = new_name
	movement = new_movement

func move() -> String:
	return char_name + " " + movement.move()

# main.gd
var bat := Character.new("Bat", Walk.new())
print(bat.move()) # Bat הולך
bat.movement = Fly.new()
print(bat.move()) # Bat עף

כאן Walk ו־Fly מרחיבים מחלקת Movement קטנה: שתי הטכניקות פועלות יחד. מחלקת GDScript יכולה לבצע extend למחלקה אחת בלבד, ולכן הרכבה היא גם הדרך שבה אובייקט אחד מקבל כמה יכולות, על ידי החזקה בכמה חלקים.

השתמשו בירושה עבור קשר אמיתי ובלתי משתנה של "הוא סוג של". השתמשו בהרכבה כאשר למחלקה "יש" משהו, או כאשר צריך להחליף את החלק בזמן שהמשחק רץ.

challenge icon

אתגר

קל

אביר לא יורש מנשק: לאביר יש נשק, והוא יכול להחליף אותו. בנו את שתי המחלקות.

  • Weapon מאחסנת את weapon_name ואת damage, ושניהם נקבעים על ידי הבנאי: Weapon.new("Sword", 7).
  • Knight מאחסנת את knight_name (מהבנאי) ונשק, שערכו null בהתחלה.
  • equip(new_weapon) מחליפה את הנשק, ו-drop() מחזירה אותו לערך null.
  • attack() מחזירה את Ada attacks with Sword for 7 damage, תוך שימוש בשם האביר ובשם הנשק ובנזק שלו, או את Ada has no weapon כשאין נשק.

הקוד שסופק קורא את שם האביר ואת מספר הפקודות שאחריו (equip Sword 7, drop, attack) ומריץ אותן. עבור Ada ו-attack, equip Sword 7, attack, equip Axe 12, attack, drop, attack הוא מדפיס:

Ada has no weapon
Equipped Sword
Ada attacks with Sword for 7 damage
Equipped Axe
Ada attacks with Axe for 12 damage
Dropped the weapon
Ada has no weapon

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

נסו בעצמכם

extends Node

func _ready():
	# קוד הקלט/פלט שסופק: יש להשאיר אותו כפי שהוא
	var knight := Knight.new(OS.read_string_from_stdin())
	var count := int(OS.read_string_from_stdin())
	for i in count:
		var parts := OS.read_string_from_stdin().split(" ")
		if parts[0] == "equip":
			knight.equip(Weapon.new(parts[1], int(parts[2])))
			print("Equipped ", parts[1])
		elif parts[0] == "drop":
			knight.drop()
			print("Dropped the weapon")
		else:
			print(knight.attack())
quiz iconבחנו את עצמכם

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

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

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