توسيع الـ Constructor
جزء من قسم البرمجة كائنية التوجه في رحلة Lua على Coddy — الدرس 33 من 70.
عندما ترث فئة تابعة (child class) من فئة أساسية (parent class)، فإنك غالباً ما ترغب في أن يقوم منشئ الفئة التابعة (constructor) بتهيئة كل ما تقوم الفئة الأساسية بتهيئته، بالإضافة إلى أي حقول إضافية خاصة بالفئة التابعة. وبدلاً من تكرار الكود، يمكنك استدعاء منشئ الفئة الأساسية مباشرةً.
تتضمن هذه التقنية استخدام اسم الفئة الأب (parent class) لاستدعاء التابع :new() الخاص بها، مع تمرير self كمعامل أول. يؤدي هذا إلى إنشاء الكائن الأساسي مع كافة عمليات تهيئة الأب، والتي تقوم بعد ذلك بتخصيصها للابن.
local Vehicle = {}
Vehicle.__index = Vehicle
function Vehicle:new(speed)
local obj = {speed = speed}
setmetatable(obj, Vehicle)
return obj
end
-- Car يرث من Vehicle
local Car = {}
Car.__index = Car
setmetatable(Car, {__index = Vehicle})
function Car:new(speed, brand)
local obj = Vehicle.new(Vehicle, speed) -- استدعاء منشئ الأب
obj.brand = brand -- إضافة حقل خاص بالابن
setmetatable(obj, Car) -- إعادة الربط بـ Car
return obj
endلاحظ الخطوات الرئيسية في منشئ الفئة الفرعية (child constructor): أولاً، نقوم باستدعاء Vehicle.new(Vehicle, speed) للحصول على كائن يحتوي على حقل speed معد مسبقاً. ثم نقوم بإضافة حقل brand الخاص بالفئة الفرعية. أخيراً، نقوم بتغيير الجدول الوصفي (metatable) من Vehicle إلى Car حتى يبحث الكائن عن الدوال في الفئة الفرعية أولاً.
يمكنك أيضًا استخدام صيغة النقطتين الرأسيتين عند استدعاء منشئ الفئة الأب — Vehicle:new(speed) تعادل Vehicle.new(Vehicle, speed)، بما أن كليهما يمرر Vehicle كوسيط أول. كلا الشكلين يعملان بشكل صحيح هنا، لذا لا تتردد في استخدام أيهما تجده أكثر قابلية للقراءة.
local myCar = Car:new(120, "Toyota")
print(myCar.speed) -- المخرجات: 120
print(myCar.brand) -- المخرجات: Toyotaهذا النمط يحافظ على كودك بنظام DRY—حيث يقع منطق التهيئة المشترك في الفئة الأب (parent)، بينما يتعامل كل تابع (child) فقط مع سماته الفريدة.
التحدي
سهللنقم ببناء تسلسل هرمي للكائنات حيث تمدد الفئة الابنة (child class) منشئ الفئة الأب (parent class)! ستقوم بإنشاء فئة أب باسم Animal وفئة ابنة باسم Bird، حيث يستدعي منشئ Bird منشئ Animal للتعامل مع التهيئة المشتركة قبل إضافة سمته الفريدة الخاصة.
ستقوم بتنظيم الكود الخاص بك عبر ثلاثة ملفات:
Animal.lua: قم بتعريف الفئة الأب باستخدام منشئ:new(name)الذي يخزن اسم الحيوان. قم بتضمين تابع:describe()يطبع اسم الحيوان. قم بإعداد نمط الفئة القياسي باستخدام__indexوأعد الفئة.Bird.lua: قم بتعريف الفئة الابنة التي ترث من Animal. يجب أن يستدعي منشئ:new(name, wingspan)الخاص بـ Bird منشئ الأب باستخدامAnimal.new(Animal, name)لتهيئة الاسم، ثم إضافة حقلwingspanإلى الكائن، وأخيراً إعادة ربط الـ metatable بـ Bird. قم بتضمين تابع:info()يطبع كلاً من الاسم وطول جناحي الطائر بتنسيق محدد.main.lua: اطلب وحدة Bird، واقرأ مدخلين (الاسم وطول الجناحين)، وأنشئ مثيلاً (instance) من Bird، واستدعِ كلا التابعين لإثبات أن الوظائف الموروثة والخاصة بالابن تعمل معاً.
ستتلقى مدخلين:
- اسم الطائر
- طول جناحي الطائر (رقم)
في ملفك الرئيسي، أنشئ Bird بالاسم وطول الجناحين المعطيين. ثم استدعِ :describe() متبوعاً بـ :info() في أسطر منفصلة.
يجب أن يطبع التابع :describe() (الموروث من Animal):
Animal: {name}يجب أن يطبع التابع :info() (المعرف في Bird):
{name} has a wingspan of {wingspan}على سبيل المثال، إذا كانت المدخلات هي Eagle و 200، يجب أن يكون الناتج:
Animal: Eagle
Eagle has a wingspan of 200المفتاح هنا هو أن منشئ Bird لا يكرر تهيئة الاسم — بل يفوض هذا العمل لمنشئ Animal، ثم يضيف فقط ما هو فريد للطيور. هذا يحافظ على كودك نظيفاً (DRY) مع بناء سلسلة وراثة صحيحة!
جرّب بنفسك
-- main.lua: نقطة الدخول
local Bird = require('Bird')
-- قراءة المدخلات
local name = io.read()
local wingspan = tonumber(io.read())
-- TODO: إنشاء كائن Bird بالاسم و wingspan المعطيين
-- TODO: استدعاء :describe() على الطائر (موروثة من Animal)
-- TODO: استدعاء :info() على الطائر (معرفة في Bird)
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس البرمجة كائنية التوجه
4مشروع: بنك رقمي
إعداد المشروعطريقة الإيداع7تعدد الأشكال وإعادة التعريف
إعادة تعريف الدوالاستدعاء دوال الفئة الأبDuck Typingواجهة مشتركةالتحقق من النوعمراجعة - أدوار الموظفين2نمط النموذج الأولي للفئات
مفهوم النموذج الأوليالربط باستخدام __indexالمنشئ :new()تهيئة الخصائصنسخ مستقلةملخص - مصنع السيارات5تحميل المعاملات في OOP
جمع الكائناتطرح الكائناتدمج الكائناتمقارنة الكائنات (<, >)مراجعة - رياضيات المحفظة8التغليف
اصطلاحات التسميةاستخدام Closures للخصوصيةالوصول عبر Closuresجداول للقراءة فقطمنطق التحقق من الصحةمراجعة - الخزنة الآمنة11أنماط التصميم (مبسط)
دوال المصنعجدول Singletonنمط الـ Iteratorالمراقب (المستمع)مراجعة - مصنع الـ Logger3حالة الكائن وسلوكه
متغيرات النسخةدالات الجلب (Getter Methods)دالات التعيين (Setter Methods)الخصائص المحسوبةتنسيق النصوصالتحقق من المساواةمراجعة - درجة الطالب6أساسيات الوراثة
إعداد الوراثةوراثة الـ Methodsتوسيع الـ Constructorإضافة Methods للابنالمشترك مقابل الفريدملخص - التسلسل الهرمي للأشكال