المشترك مقابل الفريد
جزء من قسم Object Oriented Programming في رحلة Lua على Coddy — الدرس 35 من 70.
عند العمل مع الوراثة، من المهم فهم أين يوجد كل جزء من البيانات. بعض السمات تكون مشتركة—تُعرّف في الفئة الأب وتكون متاحة لجميع الأبناء. والبعض الآخر فريد—يتم إنشاؤه خصيصاً في الفئة الابن أو النسخة (instance).
تأمل هذا التسلسل الهرمي:
local Animal = {}
Animal.__index = Animal
Animal.kingdom = "Animalia" -- مشترك: مُعرّف في الفئة
function Animal:new(name)
local obj = {name = name} -- فريد: مخزن في كل مثيل
setmetatable(obj, Animal)
return obj
endlocal Dog = {}
Dog.__index = Dog
setmetatable(Dog, {__index = Animal})
Dog.sound = "bark" -- مشترك بين جميع الكلاب
function Dog:new(name, breed)
local obj = Animal.new(Animal, name)
obj.breed = breed -- فريد: كل كلب له سلالته الخاصة
setmetatable(obj, Dog)
return obj
endعندما تقوم بإنشاء مثيل (instance) لـ Dog، توجد بعض القيم مباشرة على الكائن (object) بينما يتم العثور على قيم أخرى من خلال سلسلة البحث (lookup chain):
local rex = Dog:new("Rex", "German Shepherd")
-- فريد لهذا المثيل (مخزن في rex)
print(rex.name) -- "Rex"
print(rex.breed) -- "German Shepherd"-- مشترك (تم العثور عليه عبر البحث)
print(rex.sound) -- "bark" (من Dog)
print(rex.kingdom) -- "Animalia" (من Animal)التمييز الأساسي: الحقول المسندة إلى obj في المنشئات (constructors) تكون فريدة لكل مثيل، بينما الحقول المعرفة مباشرة على جداول الفئات (class tables) تتم مشاركتها عبر جميع مثيلات تلك الفئة وفئاتها الفرعية.
التحدي
سهلدعنا نستكشف كيف تتدفق البيانات عبر تسلسل هرمي للوراثة من خلال بناء نظام فئات Creature و Dragon. ستكتشف بنفسك أي السمات يتم مشاركتها عبر جميع النسخ (instances) وأيها فريد لكل كائن فردي.
ستقوم بتنظيم الكود الخاص بك عبر ثلاثة ملفات:
Creature.lua: قم بتعريف الفئة الأب (parent class) مع سمة مشتركة على مستوى الفئةworld = "Fantasy Realm"تشترك فيها جميع المخلوقات. قم بتضمين منشئ:new(name)يقوم بتخزين اسم المخلوق كسمة نسخة (instance attribute).Dragon.lua: قم بتعريف الفئة الابن (child class) التي ترث من Creature. أضف سمة مشتركة على مستوى الفئةelement = "fire"تشترك فيها جميع التنانين. يجب أن يستدعي منشئك:new(name, color)منشئ الأب للاسم، ثم يضيفcolorكسمة نسخة فريدة لكل تنين.main.lua: قم بإنشاء تنينين مختلفين وافحص سماتهما لتوضيح الفرق بين البيانات المشتركة والفريدة.
ستتلقى مدخلين:
- اسم ولون التنين الأول، مفصولين بفاصلة (على سبيل المثال،
Smaug,red) - اسم ولون التنين الثاني، مفصولين بفاصلة (على سبيل المثال،
Draco,gold)
في ملفك الرئيسي، قم بإنشاء كلا التنينين بأسمائهما وألوانهما الخاصة. ثم اطبع المعلومات التالية بهذا الترتيب الدقيق:
nameالخاص بالتنين الأولcolorالخاص بالتنين الأولnameالخاص بالتنين الثانيcolorالخاص بالتنين الثانيelementالخاص بالتنين الأول (مشترك من فئة Dragon)elementالخاص بالتنين الثاني (مشترك من فئة Dragon)worldالخاص بالتنين الأول (مشترك من فئة Creature)
على سبيل المثال، إذا كانت المدخلات هي Smaug,red و Draco,gold، يجب أن يكون المخرج:
Smaug
red
Draco
gold
fire
fire
Fantasy Realmلاحظ كيف أن name و color مختلفان لكل تنين (سمات نسخة فريدة)، بينما element و world هما نفسهما لكليهما (سمات فئة مشتركة يتم العثور عليها من خلال سلسلة البحث lookup chain).
ورقة مرجعية
في هرميات الوراثة، يمكن أن تكون السمات إما مشتركة (يتم تعريفها في جدول الفئة) أو فريدة (يتم تخزينها في النسخ الفردية).
يتم تعريف السمات المشتركة مباشرة في جداول الفئات ويتم الوصول إليها من خلال سلسلة البحث في الجدول الوصفي (metatable lookup chain):
local Animal = {}
Animal.__index = Animal
Animal.kingdom = "Animalia" -- Shared across all Animalsيتم تعيين السمات الفريدة لكائن النسخة (obj) في الدوال الإنشائية (constructors):
function Animal:new(name)
local obj = {name = name} -- Unique to each instance
setmetatable(obj, Animal)
return obj
endيمكن أن تمتلك الفئات الفرعية سماتها المشتركة الخاصة بها مع وراثة سمات الفئة الأب:
local Dog = {}
Dog.__index = Dog
setmetatable(Dog, {__index = Animal})
Dog.sound = "bark" -- Shared among all Dogs
function Dog:new(name, breed)
local obj = Animal.new(Animal, name) -- Call parent constructor
obj.breed = breed -- Add unique child attribute
setmetatable(obj, Dog)
return obj
endالوصول إلى السمات:
local rex = Dog:new("Rex", "German Shepherd")
-- Unique (stored directly on rex)
print(rex.name) -- "Rex"
print(rex.breed) -- "German Shepherd"
-- Shared (found via metatable lookup)
print(rex.sound) -- "bark" (from Dog class)
print(rex.kingdom) -- "Animalia" (from Animal class)جرّب بنفسك
-- main.lua: إنشاء التنانين وتوضيح السمات المشتركة مقابل الفريدة
local Dragon = require('Dragon')
-- قراءة المدخلات للتنين الأول (الاسم، اللون)
local input1 = io.read()
-- قراءة المدخلات للتنين الثاني (الاسم، اللون)
local input2 = io.read()
-- TODO: تحليل المدخل الأول لاستخراج الاسم واللون
-- تلميح: استخدم string.match مع النمط "([^,]+),([^,]+)"
-- TODO: تحليل المدخل الثاني لاستخراج الاسم واللون
-- TODO: إنشاء التنين الأول باسمه ولونه
-- TODO: إنشاء التنين الثاني باسمه ولونه
-- TODO: اطبع ما يلي بالترتيب:
-- 1. اسم التنين الأول
-- 2. لون التنين الأول
-- 3. اسم التنين الثاني
-- 4. لون التنين الثاني
-- 5. عنصر التنين الأول (مشترك من فئة Dragon)
-- 6. عنصر التنين الثاني (مشترك من فئة Dragon)
-- 7. عالم التنين الأول (مشترك من فئة Creature)
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس 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 للابنالمشترك مقابل الفريدملخص - التسلسل الهرمي للأشكال