Menu
CoddyTech

מחלקות ומתודות אבסטרקטיות

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

יש מחלקות שקיימות רק כדי להרחיב אותן. לכל צורה יש שטח, אבל אי אפשר לחשב אותו עד שיודעים אם הצורה היא עיגול או מלבן. סמנו מחלקה כזאת ב-@abstract, בשורה שמעל class_name:

# shape.gd
@abstract
class_name Shape
extends RefCounted

@abstract func area() -> float
@abstract func perimeter() -> float

func describe() -> String:
	return "Area %.1f, perimeter %.1f" % [area(), perimeter()]

ל־@abstract func יש חתימה ואין גוף: אין נקודתיים ואין קוד אחריו. הוא מציין שכל מחלקת צאצא חייבת לספק את המתודה הזו. describe() היא מתודה רגילה; מחלקות צאצא יורשות אותה, והיא כבר יכולה לקרוא למתודות המופשטות.

אי אפשר ליצור אובייקט של מחלקה מופשטת. Shape.new() עוצר את התוכנית לפני שהיא מתחילה עם Parse Error: Cannot construct abstract class "Shape".

מחלקת בת שמממשת כל מתודה מופשטת היא מחלקה רגילה:

# rectangle.gd
class_name Rectangle
extends Shape

var width: float
var height: float

func _init(w: float, h: float) -> void:
	width = w
	height = h

func area() -> float:
	return width * height

func perimeter() -> float:
	return 2 * (width + height)
var rect := Rectangle.new(4.0, 6.0)
print(rect.describe())
Area 24.0, perimeter 20.0

אם מחלקת־בת משמיטה אחת מהן, Godot מדווח על כך לפני ההרצה: Class "Square" must implement "Shape.perimeter()" and other inherited abstract methods or be marked as "@abstract". לכן לכל אובייקט שאפשר ליצור יש area() ו־perimeter().

למחלקה מופשטת עדיין יכולים להיות משתנים ו-_init(). מחלקות יורשות קוראות לו באמצעות super() כרגיל.

challenge icon

אתגר

קל

חנות מקבלת שני אמצעי תשלום. לכל תשלום יש סכום וקבלה, אבל העמלה והשם תלויים באמצעי התשלום.

  • הפוך את PaymentMethod למחלקה מופשטת והצהר על שתי מתודות מופשטות: fee() -> float ו-method_name() -> String. כתוב את receipt(), שמחזירה NAME: paid AMOUNT, fee FEE, total TOTAL עם שתי ספרות אחרי הנקודה העשרונית עבור כל מספר (הסכום הכולל הוא הסכום בתוספת העמלה).
  • CreditCard: העמלה היא 3% מהסכום (amount * 0.03), והשם הוא Credit card.
  • BankTransfer: העמלה היא 1.5, או 0.0 כשהסכום הוא 100 או יותר, והשם הוא Bank transfer.

מחלקות הבת משתמשות בבנאי של PaymentMethod. הקוד שסופק קורא כמה תשלומים מופיעים בהמשך, ואז שורה אחת לכל תשלום: card AMOUNT או transfer AMOUNT. הוא מדפיס כל קבלה ואת סכום העמלות. עבור card 50 ו-transfer 120 הוא מדפיס:

Credit card: paid 50.00, fee 1.50, total 51.50
Bank transfer: paid 120.00, fee 0.00, total 120.00
Total fees: 1.50

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

נסו בעצמכם

extends Node

func _ready():
	# קוד הקלט/פלט שסופק: יש להשאיר אותו כפי שהוא
	var count := int(OS.read_string_from_stdin())
	var total_fees := 0.0
	for i in count:
		var p := OS.read_string_from_stdin().split(" ")
		var payment: PaymentMethod
		if p[0] == "card":
			payment = CreditCard.new(float(p[1]))
		else:
			payment = BankTransfer.new(float(p[1]))
		print(payment.receipt())
		total_fees += payment.fee()
	print("Total fees: %.2f" % total_fees)
quiz iconבחנו את עצמכם

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

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

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