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

التركيب مقابل الوراثة

جزء من قسم البرمجة كائنية التوجّه في رحلة 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 عبر الإنترنت