الخصائص المحسوبة
جزء من قسم Object Oriented Programming في رحلة Lua على Coddy — الدرس 15 من 70.
توفر أدوات الجلب (Getters) والتعيين (Setters) إمكانية الوصول إلى القيم المخزنة، ولكن في بعض الأحيان تحتاج إلى بيانات لا توجد كحقل مخزن—بل يجب حسابها من سمات أخرى. تُسمى هذه الخصائص المحسوبة.
فكر في مستطيل. أنت تقوم بتخزين عرضه وارتفاعه، لكن المساحة لا يتم تخزينها في أي مكان - بل يتم حسابها بضرب هاتين القيمتين معاً. وبدلاً من تخزين بيانات زائدة، يمكنك إنشاء دالة (method) تقوم بحساب النتيجة وإرجاعها:
local Rectangle = {}
Rectangle.__index = Rectangle
function Rectangle:new(width, height)
local instance = {}
setmetatable(instance, self)
instance.width = width
instance.height = height
return instance
end
function Rectangle:getArea()
return self.width * self.height
endلا تقوم طريقة :getArea() بإرجاع قيمة مخزنة—بل تقوم بحساب المساحة من جديد في كل مرة تستدعيها فيها. يتميز هذا النهج بميزة رئيسية: إذا تغير العرض أو الارتفاع، تعكس المساحة الأبعاد الجديدة تلقائيًا دون الحاجة إلى تحديث أي شيء.
local box = Rectangle:new(5, 3)
print(box:getArea()) -- الناتج: 15
box.width = 10
print(box:getArea()) -- الناتج: 30تحافظ الخصائص المحسوبة (Calculated properties) على اتساق كائناتك. فبدلاً من تخزين القيم التي تعتمد على حقول أخرى (والمخاطرة بأن تصبح قديمة)، يمكنك حسابها عند الطلب. ينطبق هذا النمط على أي بيانات مشتقة—مثل المحيطات، أو المتوسطات، أو السلاسل النصية المنسقة، أو أي قيمة يمكن تحديدها من السمات الموجودة.
التحدي
سهللنقم ببناء فئة Box تقوم بحساب حجمها عند الطلب! بدلاً من تخزين الحجم كحقل، ستقوم بإنشاء خاصية محسوبة تحسبه من أبعاد الصندوق كلما دعت الحاجة.
ستقوم بتنظيم الكود الخاص بك عبر ملفين:
Box.lua: قم بتعريف فئةBoxالخاصة بك باستخدام نمط النموذج الأولي (prototype pattern) القياسي. يخزن كل صندوق ثلاثة أبعاد:width، وheight، وdepth. قم بتضمين:- منشئ
:new(width, height, depth)يقوم بتخزين الأبعاد الثلاثة جميعها - طريقة
:getVolume()تقوم بحساب وإرجاع الحجم (width × height × depth) - طريقة
:getSurfaceArea()تقوم بحساب وإرجاع إجمالي مساحة السطح
- منشئ
main.lua: قم باستدعاء وحدة Box الخاصة بك، وأنشئ مثيلاً (instance) للصندوق، ووضح كيف تعكس الخصائص المحسوبة الأبعاد الحالية تلقائيًا.
يتم حساب مساحة سطح الصندوق كالتالي: 2 × (width×height + height×depth + width×depth)
ستتلقى ثلاثة مدخلات تمثل أبعاد الصندوق:
- العرض (Width)
- الارتفاع (Height)
- العمق (Depth)
في ملفك الرئيسي، أنشئ صندوقًا بالأبعاد المعطاة، ثم اطبع سطرين:
- الحجم باستخدام
:getVolume() - مساحة السطح باستخدام
:getSurfaceArea()
على سبيل المثال، إذا كانت المدخلات هي 3، و 4، و 5، يجب أن يكون المخرج:
60
94جمال الخصائص المحسوبة هو أنها تظل دقيقة دائمًا. إذا قمت لاحقًا بتغيير أحد أبعاد الصندوق، فإن استدعاء :getVolume() مرة أخرى سيعيد القيمة الجديدة الصحيحة تلقائيًا — دون الحاجة إلى تحديثات يدوية!
ورقة مرجعية
الخصائص المحسوبة هي دوال تقوم بحساب وإرجاع قيم بناءً على سمات أخرى بدلاً من تخزينها مباشرة. يضمن ذلك اتساق البيانات ويزيل التكرار.
مثال على خاصية محسوبة للمساحة:
local Rectangle = {}
Rectangle.__index = Rectangle
function Rectangle:new(width, height)
local instance = {}
setmetatable(instance, self)
instance.width = width
instance.height = height
return instance
end
function Rectangle:getArea()
return self.width * self.height
endتقوم الدالة :getArea() بحساب المساحة في كل مرة يتم استدعاؤها، مما يعكس تلقائياً أي تغييرات تطرأ على العرض أو الارتفاع:
local box = Rectangle:new(5, 3)
print(box:getArea()) -- المخرجات: 15
box.width = 10
print(box:getArea()) -- المخرجات: 30الخصائص المحسوبة مفيدة لأي بيانات مشتقة مثل المحيطات، أو الأحجام، أو المتوسطات، أو السلاسل النصية المنسقة التي يمكن تحديدها من السمات الموجودة.
جرّب بنفسك
-- استدعاء وحدة Box
local Box = require('Box')
-- قراءة أبعاد المدخلات
local width = tonumber(io.read())
local height = tonumber(io.read())
local depth = tonumber(io.read())
-- TODO: إنشاء مثيل للصندوق بالأبعاد المعطاة
-- TODO: طباعة الحجم باستخدام ()getVolume:
-- TODO: طباعة مساحة السطح باستخدام ()getSurfaceArea:
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس 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 للابنالمشترك مقابل الفريدملخص - التسلسل الهرمي للأشكال