توسيع الـ Constructor
جزء من قسم البرمجة كائنية التوجه في رحلة Lua على Coddy. الدرس 33 من 70.
عندما يرث child من parent، غالبًا ما تريد أن يهيّئ constructor الخاص بـ child كل ما كان سيهيّئه parent، بالإضافة إلى أي field إضافي خاص بـ child. وبدلًا من تكرار الشيفرة، يمكنك استدعاء constructor الخاص بـ parent مباشرةً.
تتضمن التقنية استخدام اسم الفئة الأصلية لاستدعاء أسلوبها :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: أولًا، نستدعي Vehicle.new(Vehicle, speed) للحصول على كائن تم تعيين الحقل speed فيه مسبقًا. ثم نضيف الحقل الخاص بـ child، وهو brand. وأخيرًا، نغيّر metatable من Vehicle إلى Car بحيث يبحث instance عن methods في الفئة الابنة أولًا.
يمكنك أيضًا استخدام صياغة النقطتين عند استدعاء مُنشئ parent: Vehicle:new(speed) مكافئة لـ Vehicle.new(Vehicle, speed)، لأن كليهما يمرّر Vehicle باعتباره الوسيطة الأولى. تعمل كلتا الصياغتين بشكل صحيح هنا، لذا لا تتردد في استخدام أيهما تجده أكثر قابلية للقراءة.
local myCar = Car:new(120, "Toyota")
print(myCar.speed) -- الناتج: 120
print(myCar.brand) -- الناتج: Toyotaيحافظ هذا النمط على جفاف شفرتك: إذ يوجد منطق التهيئة المشترك في parent، بينما يتولى كل child سماته الفريدة فقط.
التحدي
سهللنَبْنِ تسلسلًا هرميًا للمخلوقات، حيث يوسّع صنف فرعي مُنشئ صنفه الأب! ستنشئ صنفًا أبًا هو Animal وصنفًا فرعيًا هو Bird، بحيث يستدعي مُنشئ Bird مُنشئ Animal لمعالجة التهيئة المشتركة قبل إضافة سِمته الفريدة.
ستنظّم التعليمات البرمجية عبر ثلاثة ملفات:
Animal.lua: عرّف صنفك الأب باستخدام مُنشئ:new(name)الذي يخزّن اسم الحيوان. أضف أسلوب:describe()يطبع اسم الحيوان. أعد إعداد نمط الصنف القياسي باستخدام__indexوأعِد الصنف.Bird.lua: عرّف صنفك الفرعي الذي يرث منAnimal. يجب أن يستدعي مُنشئBirdذي الصيغة:new(name, wingspan)مُنشئ الصنف الأب باستخدامAnimal.new(Animal, name)لتهيئة الاسم، ثم يضيف الحقلwingspanإلى الكائن، وأخيرًا يعيد ربط جدول التعريفات الوصفية بـBird. أضف أسلوب:info()يطبع الاسم وباع الجناحين بتنسيق محدد.main.lua: اطلب وحدةBird، واقرأ مُدخلين (الاسم وباع الجناحين)، وأنشئ كائنًا من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 بالـ name و 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 للابنالمشترك مقابل الفريدملخص - التسلسل الهرمي للأشكالتدرّب بنفسك: مترجم Lua عبر الإنترنت