التركيب مقابل الوراثة
جزء من قسم البرمجة كائنية التوجّه في رحلة 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 لتوسيع فئة واحدة فقط، لذا فإن التركيب هو أيضًا طريقة حصول كائن واحد على قدرات متعددة، وذلك باحتوائه على أجزاء متعددة.
استخدم الوراثة لعلاقة حقيقية من نوع «هو» لا تتغير أبدًا. واستخدم التركيب عندما يكون لدى الصنف شيء ما، أو عندما يجب تبديل الجزء أثناء تشغيل اللعبة.
التحدي
سهلالفارس لا يرث من السلاح: بل يمتلك الفارس سلاحًا، ويمكنه تبديله. أنشئ الصنفين.
- يخزّن
Weaponكلًا منweapon_nameوdamage، ويُحدَّدان بواسطة المُنشئ:Weapon.new("Sword", 7). - يخزّن
Knightknight_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())
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس البرمجة كائنية التوجّه
1أساسيات البرمجة كائنية التوجه
الملفات الخارجيةمقدمة إلى البرمجة كائنية التوجهالفئات مقابل الكائناتالكلمة المفتاحية selfالأساليبالخصائصالمُنشئ (_init)مراجعة - آلة حاسبة بسيطة4تعدد الأشكال
إعادة النظر في تجاوز الأساليبكتابة الأنواع بأسلوب البطةالفئات والأساليب المجرّدةتصميم الواجهاتمراجعة - حاسبة الأشكال10أنماط التصميم، الجزء الثاني
نمط الأوامرنمط المحوّلنمط المُزيّننمط الطريقة القالبيةنمط الحالةالنمط المركّب2خصائص الأصناف
متغيرات الكائن مقابل المتغيرات الساكنةالدوال الساكنةمُعيِّنات الخصائصمُسترجِعات الخصائصخاص وفقًا للاتفاقيةمراجعة - مدير الحسابات البنكية5التغليف
الأعضاء العامة والخاصةالتحقق من الصحة باستخدام دوال الضبطإخفاء المعلوماتالخصائص للقراءة فقطمراجعة - نظام سجلات الطلاب8مفاهيم متقدمة في البرمجة كائنية التوجه
التركيب مقابل الوراثةالأصناف الداخليةالعُقد كمكوّناتRefCounted مقابل Nodeالتعدادات في الأصنافتدرّب بنفسك: مترجم GDScript عبر الإنترنت