متغيرات النسخة
جزء من قسم Object Oriented Programming في رحلة Lua على Coddy — الدرس 12 من 70.
مرحباً بك في فصل جديد يركز على كيفية إدارة الكائنات لبياناتها الداخلية. لقد تعلمت كيفية إنشاء الفئات (classes) والنماذج (instances) — والآن حان الوقت لاستكشاف كيفية قيام كل نموذج بتخزين وإدارة حالته الفريدة.
متغيرات النسخة (Instance variables) هي حقول تنتمي حصرياً لكائن واحد. عندما تقوم بتعيين قيمة لـ self.something داخل دالة (method) أو منشئ (constructor)، فإن تلك البيانات تعيش فقط في تلك النسخة المحددة. الكائنات الأخرى من نفس الفئة (class) لديها نسخها المنفصلة الخاصة بها.
يصبح هذا مهماً بشكل خاص عند تخزين بيانات معقدة مثل الجداول. فكر في نظام مخزون حيث يحمل كل شخصية عناصر مختلفة:
local Inventory = {}
Inventory.__index = Inventory
function Inventory:new()
local instance = {}
setmetatable(instance, self)
instance.items = {} -- تحصل كل نسخة على جدول فارغ خاص بها
return instance
end
function Inventory:addItem(item)
table.insert(self.items, item)
endالسطر الأساسي هو instance.items = {}. من خلال إنشاء جدول فارغ جديد داخل المنشئ (constructor)، يحصل كل كائن مخزون (inventory object) على قائمته المستقلة الخاصة به. إذا قمت بدلاً من ذلك بتعريف items في جدول الفئة (class table) نفسه، فإن جميع النسخ (instances) ستتشارك نفس الجدول عن طريق الخطأ - فإضافة سيف لشخصية واحدة سيمنحه للجميع!
local bag1 = Inventory:new()
local bag2 = Inventory:new()
bag1:addItem("Sword")
bag2:addItem("Potion")
print(#bag1.items) -- المخرجات: 1
print(#bag2.items) -- المخرجات: 1كل مخزون يحتفظ بمجموعته الخاصة. ينطبق هذا النمط كلما احتاج مثيل (instance) إلى تتبع بيانات تتغير بشكل مستقل—القوائم، أو العدادات، أو أي حالة متغيرة (mutable state) فريدة لهذا الكائن.
التحدي
سهللنقم ببناء نظام ShoppingCart حيث تحتفظ كل عربة تسوق بقائمة منتجات منفصلة خاصة بها. سيوضح هذا كيف تحافظ متغيرات النسخة (instance variables) على عزل البيانات بين الكائنات - فإضافة عناصر إلى عربة واحدة لن تؤثر على الأخرى!
ستقوم بتنظيم الكود الخاص بك عبر ملفين:
ShoppingCart.lua: قم بتعريف فئةShoppingCartحيث تمتلك كل نسخة جدولproductsالخاص بها. قم بتضمين:- منشئ
:new()يقوم بتهيئة قائمة منتجات فارغة لكل عربة. - طريقة
:addProduct(productName)تضيف منتجاً إلى قائمة هذه العربة. - طريقة
:listProducts()تقوم بطباعة كل منتج في سطر منفصل.
- منشئ
main.lua: اطلب وحدة ShoppingCart وقم بإنشاء عربتي تسوق منفصلتين. أضف منتجات مختلفة إلى كل عربة لإثبات أنها تحتفظ بمخزونات مستقلة.
ستتلقى أربعة مدخلات:
- المنتج الأول لإضافته إلى العربة A
- المنتج الثاني لإضافته إلى العربة A
- المنتج الأول لإضافته إلى العربة B
- المنتج الثاني لإضافته إلى العربة B
في ملفك الرئيسي:
- قم بإنشاء عربتي تسوق:
cartAوcartB - أضف أول منتجين إلى
cartA - أضف آخر منتجين إلى
cartB - اطبع
Cart A:ثم اسرد منتجات العربة A - اطبع
Cart B:ثم اسرد منتجات العربة B
على سبيل المثال، إذا كانت المدخلات هي Apple، و Bread، و Milk، و Eggs، يجب أن يكون المخرج:
Cart A:
Apple
Bread
Cart B:
Milk
Eggsتذكر: المفتاح هو تهيئة products كجدول فارغ جديد داخل المنشئ. يضمن ذلك حصول كل نسخة من العربة على قائمتها المنفصلة بدلاً من مشاركة جدول واحد عبر جميع العربات.
ورقة مرجعية
متغيرات النسخة (Instance variables) هي حقول تنتمي حصرياً لكائن واحد. عندما تقوم بتعيين قيمة لـ self.something داخل دالة أو منشئ (constructor)، فإن تلك البيانات تعيش فقط في تلك النسخة المحددة.
لإنشاء متغيرات النسخة، قم بتهيئتها داخل المنشئ باستخدام جدول جديد لكل نسخة:
local Inventory = {}
Inventory.__index = Inventory
function Inventory:new()
local instance = {}
setmetatable(instance, self)
instance.items = {} -- Each instance gets its own empty table
return instance
end
function Inventory:addItem(item)
table.insert(self.items, item)
endالمفتاح هو instance.items = {}—إنشاء جدول فارغ جديد داخل المنشئ يضمن حصول كل كائن على بياناته المتميزة الخاصة به. إذا قمت بتعريف items في جدول الفئة (class table) نفسه، فستتشارك جميع النسخ نفس الجدول.
local bag1 = Inventory:new()
local bag2 = Inventory:new()
bag1:addItem("Sword")
bag2:addItem("Potion")
print(#bag1.items) -- Output: 1
print(#bag2.items) -- Output: 1تحافظ كل نسخة على مجموعتها الخاصة بشكل مستقل. ينطبق هذا النمط على أي حالة متغيرة (mutable state) فريدة لكائن ما—مثل القوائم، العدادات، أو البيانات الأخرى التي تتغير لكل نسخة.
جرّب بنفسك
-- استيراد وحدة ShoppingCart
local ShoppingCart = require('ShoppingCart')
-- قراءة المدخلات
local product1 = io.read()
local product2 = io.read()
local product3 = io.read()
local product4 = io.read()
-- TODO: إنشاء عربتي تسوق: cartA و cartB
-- TODO: إضافة product1 و product2 إلى cartA
-- TODO: إضافة product3 و product4 إلى cartB
-- TODO: طباعة "Cart A:" ثم عرض قائمة منتجات cartA
-- TODO: طباعة "Cart B:" ثم عرض قائمة منتجات cartB
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس 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 للابنالمشترك مقابل الفريدملخص - التسلسل الهرمي للأشكال