استدعاء دوال الفئة الأب
جزء من قسم Object Oriented Programming في رحلة Lua على Coddy — الدرس 38 من 70.
أحياناً لا يكون تجاوز الطريقة (method) بالكامل هو ما تريده. بدلاً من ذلك، قد ترغب في توسيع سلوك الأب — تنفيذ ما يفعله الأب، ثم إضافة شيء إضافي. ولتحقيق ذلك، يمكنك استدعاء طريقة الأب مباشرة من داخل عملية التجاوز في الابن.
تستخدم هذه التقنية صيغة النقطة مع اسم الفئة الأب، مع تمرير self كوسيط أول بشكل صريح:
local Animal = {}
Animal.__index = Animal
function Animal:new(name)
local obj = {name = name}
setmetatable(obj, Animal)
return obj
end
function Animal:speak()
print(self.name .. " makes a sound")
end
-- Dog يوسع سلوك الأب
local Dog = {}
Dog.__index = Dog
setmetatable(Dog, {__index = Animal})
function Dog:new(name)
local obj = Animal.new(Animal, name)
setmetatable(obj, Dog)
return obj
end
function Dog:speak()
Animal.speak(self) -- استدعاء دالة الأب أولاً
print(self.name .. " wags tail happily")
endالسطر الرئيسي هو Animal.speak(self). باستخدام صيغة النقطة على الفئة الأب وتمرير self يدويًا، نقوم باستدعاء الطريقة الأصلية قبل إضافة سلوكنا الخاص:
local buddy = Dog:new("Buddy")
buddy:speak()
-- المخرجات:
-- Buddy يصدر صوتًا
-- Buddy يهز ذيله بسعادةهذا النمط مفيد عندما تؤدي الدالة الأب (parent method) عملاً هاماً لا ترغب في تكراره. يمكن للدالة الابنة (child) تشغيل منطق الدالة الأب أولاً، أو آخراً، أو حتى في منتصف الكود الخاص بها، مما يمنحك تحكماً كاملاً في كيفية دمج السلوكيات.
التحدي
سهللنقم ببناء نظام تحية حيث يقوم FormalPerson بتوسيع سلوك Person العادي! بدلاً من استبدال طريقة تعريف الشخص لنفسه تماماً، ستقوم النسخة الرسمية أولاً بالتعريف القياسي، ثم تضيف لمسة أدب إضافية.
ستقوم بتنظيم الكود الخاص بك عبر ثلاثة ملفات:
Person.lua: الفئة الأساسية (base class) الخاصة بك مع منشئ:new(name)يقوم بتخزين اسم الشخص. قم بتضمين تابع:introduce()يطبع اسم الشخص متبوعاً بـsays hi. هذا هو السلوك الأساسي الذي سيتم توسيعه.FormalPerson.lua: فئة فرعية ترث من Person. يجب أن يستدعي المنشئ الخاص بها منشئ الفئة الأب للتعامل مع الاسم. قم بإعادة تعريف (Override) التابع:introduce()، ولكن بدلاً من استبدال سلوك الأب بالكامل، استدعِ تابع الأب أولاً باستخدامPerson.introduce(self)، ثم اطبع سطراً إضافياً يحتوي على اسم الشخص متبوعاً بـbows politely.main.lua: قم باستيراد وحدة FormalPerson، واقرأ اسماً من المدخلات، وأنشئ مثيلاً (instance) من FormalPerson، واستدعِ:introduce()لرؤية السلوكين معاً.
ستتلقى مدخلاً واحداً: اسم الشخص.
عندما تستدعي :introduce() على FormalPerson، يجب أن ينتج سطرين من المخرجات — الأول من تابع الأب، والثاني من إضافة الابن:
{name} says hi
{name} bows politelyعلى سبيل المثال، إذا كان الإدخال هو Eleanor، يجب أن تكون المخرجات:
Eleanor says hi
Eleanor bows politelyالفكرة الأساسية هنا هي أن FormalPerson لا يكرر منطق "says hi" — بل يفوض هذا العمل لتابع الأب، ثم يضيف سلوكه الفريد الخاص فوقه. هذا يحافظ على نظافة الكود الخاص بك ويوضح كيف يمكن للفئات الفرعية توسيع وظائف الأب بدلاً من استبدالها!
ورقة مرجعية
لتوسيع سلوك دالة (method) من الفئة الأب بدلاً من تجاوزها بالكامل، قم باستدعاء دالة الأب من داخل دالة الابن التي تتجاوزها باستخدام صيغة النقطة وتمرير self بشكل صريح:
function ChildClass:method()
ParentClass.method(self) -- استدعاء دالة الأب
-- إضافة سلوك إضافي
endمثال كامل يوضح توسيع الدالة:
local Animal = {}
Animal.__index = Animal
function Animal:new(name)
local obj = {name = name}
setmetatable(obj, Animal)
return obj
end
function Animal:speak()
print(self.name .. " makes a sound")
end
local Dog = {}
Dog.__index = Dog
setmetatable(Dog, {__index = Animal})
function Dog:new(name)
local obj = Animal.new(Animal, name)
setmetatable(obj, Dog)
return obj
end
function Dog:speak()
Animal.speak(self) -- تنفيذ سلوك الأب أولاً
print(self.name .. " wags tail happily") -- إضافة سلوك الابن
end
local buddy = Dog:new("Buddy")
buddy:speak()
-- المخرجات:
-- Buddy makes a sound
-- Buddy wags tail happilyيمكن استدعاء دالة الأب في أي نقطة: قبل، أو بعد، أو في منتصف منطق الابن الخاص، مما يمنح تحكماً كاملاً في كيفية دمج السلوكيات.
جرّب بنفسك
-- main.lua: نقطة الدخول لنظام التحية
local FormalPerson = require('FormalPerson')
-- قراءة اسم الشخص من المدخلات
local name = io.read()
-- TODO: إنشاء مثيل من FormalPerson بالاسم المعطى
-- TODO: استدعاء الدالة introduce على مثيل FormalPerson
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس Object Oriented Programming
4مشروع: بنك رقمي
إعداد المشروعطريقة الإيداع7تعدد الأشكال وإعادة التعريف
إعادة تعريف الدوالاستدعاء دوال الفئة الأبDuck Typingواجهة مشتركةالتحقق من النوعمراجعة - أدوار الموظفين2نمط النموذج الأولي للفئات
مفهوم النموذج الأوليالربط باستخدام __indexالمنشئ :new()تهيئة الخصائصنسخ مستقلةملخص - مصنع السيارات5تحميل المعاملات في OOP
جمع الكائناتطرح الكائناتدمج الكائناتمقارنة الكائنات (<, >)مراجعة - رياضيات المحفظة8التغليف
اصطلاحات التسميةاستخدام Closures للخصوصيةالوصول عبر Closuresجداول للقراءة فقطمنطق التحقق من الصحةمراجعة - الخزنة الآمنة11أنماط التصميم (مبسط)
دوال المصنعجدول Singletonنمط الـ Iteratorالمراقب (المستمع)مراجعة - مصنع الـ Logger3حالة الكائن وسلوكه
متغيرات النسخةدالات الجلب (Getter Methods)دالات التعيين (Setter Methods)الخصائص المحسوبةتنسيق النصوصالتحقق من المساواةمراجعة - درجة الطالب6أساسيات الوراثة
إعداد الوراثةوراثة الـ Methodsتوسيع الـ Constructorإضافة Methods للابنالمشترك مقابل الفريدملخص - التسلسل الهرمي للأشكال