التحقق من المساواة
جزء من قسم Object Oriented Programming في رحلة Lua على Coddy — الدرس 17 من 70.
لقد رأيت كيف يتحكم __tostring في كيفية عرض الكائن لنفسه. دالة ميتا (metamethod) مفيدة أخرى هي __eq، والتي تحدد متى يجب اعتبار كائنين متساويين باستخدام عامل ==.
بشكل افتراضي، مقارنة جدولين باستخدام == تتحقق مما إذا كانا نفس الجدول تمامًا في الذاكرة. كائنان منفصلان ببيانات متطابقة سيُرجعان false:
local user1 = {id = 101, name = "Alice"}
local user2 = {id = 101, name = "Alice"}
print(user1 == user2) -- المخرجات: false (جداول مختلفة)باستخدام __eq، يمكنك تعريف منطق المساواة الخاص بك. في الـ class، تقوم بإضافته تماماً مثل __tostring — كدالة في جدول الـ class. لكي تعمل المساواة، يجب أن يتشارك كلا الكائنين نفس الـ metatable:
local User = {}
User.__index = User
function User:new(id, name)
local instance = {}
setmetatable(instance, self)
instance.id = id
instance.name = name
return instance
end
function User:__eq(other)
return self.id == other.id
endالآن، يُعتبر كائنا User متساويين إذا كانا يتشاركان نفس الـ ID، بغض النظر عن الحقول الأخرى:
local u1 = User:new(101, "Alice")
local u2 = User:new(101, "Bob")
local u3 = User:new(202, "Alice")
print(u1 == u2) -- النتيجة: true (نفس المعرف)
print(u1 == u3) -- النتيجة: false (معرفات مختلفة)هذا النمط ذو قيمة عندما تمثل الكائنات كيانات من العالم الحقيقي بمعرفات فريدة - مقارنة سجلات قاعدة البيانات، أو كيانات الألعاب، أو أي كائنات تكون فيها الهوية أكثر أهمية من موقعها في الذاكرة.
التحدي
سهللنقم ببناء فئة Product يمكنها تحديد ما إذا كان منتجان هما نفس العنصر — حتى عندما يتم تخزينهما في جداول مختلفة تماماً! في أنظمة التجزئة، غالباً ما يكون للمنتجات رموز SKU فريدة (وحدات حفظ المخزون)، ويجب اعتبار منتجين متساويين إذا كانا يشتركان في نفس SKU، بغض النظر عن التفاصيل الأخرى مثل تغيرات الأسعار.
ستقوم بتنظيم الكود الخاص بك عبر ملفين:
Product.lua: قم بتعريف فئةProductالخاصة بك باستخدام نمط النموذج الأولي (prototype pattern) القياسي. يجب أن يخزن كل منتجsku(المعرف الفريد) وname. قم بتنفيذ الطريقة الوصفية__eqبحيث يعتبر منتجان متساويين عندما يكون لهما نفس SKU — الاسم لا يهم في عملية المقارنة.main.lua: استدعِ وحدة Product الخاصة بك وقم بإنشاء عدة مثيلات للمنتج. قارن بينها باستخدام عامل التشغيل==لرؤية منطق المساواة المخصص الخاص بك قيد التنفيذ.
يجب أن تتضمن فئة Product الخاصة بك ما يلي:
- منشئ
:new(sku, name) - طريقة
:getInfo()تعيد سلسلة نصية بالتنسيق التالي:[sku]: [name] - الطريقة الوصفية
__eqالتي تقارن المنتجات من خلال SKU الخاص بها
ستتلقى ستة مدخلات:
- SKU للمنتج الأول
- الاسم للمنتج الأول
- SKU للمنتج الثاني
- الاسم للمنتج الثاني
- SKU للمنتج الثالث
- الاسم للمنتج الثالث
في ملفك الرئيسي، قم بإنشاء ثلاثة منتجات باستخدام المدخلات المقدمة، ثم اطبع:
- المعلومات الخاصة بكل منتج (ثلاثة أسطر)
- نتيجة مقارنة المنتج 1 مع المنتج 2
- نتيجة مقارنة المنتج 1 مع المنتج 3
على سبيل المثال، إذا كانت المدخلات هي ABC123، و Wireless Mouse، و ABC123، و Mouse (Updated)، و XYZ789، و Keyboard، فيجب أن يكون المخرج:
ABC123: Wireless Mouse
ABC123: Mouse (Updated)
XYZ789: Keyboard
true
falseلاحظ كيف أن أول منتجين متساويان (نفس SKU) على الرغم من اختلاف أسمائهما — وهذا هو بالضبط كيف تتبع أنظمة المخزون الحقيقية المنتجات من خلال تغييرات الأسماء والتحديثات!
ورقة مرجعية
يحدد التابع الوهمي (metamethod) __eq منطق مساواة مخصص للكائنات باستخدام عامل التشغيل ==.
بشكل افتراضي، تتحقق مقارنة جدولين مما إذا كانا نفس الجدول في الذاكرة:
local user1 = {id = 101, name = "Alice"}
local user2 = {id = 101, name = "Alice"}
print(user1 == user2) -- Output: false (جداول مختلفة)لتعريف مساواة مخصصة، أضف __eq كدالة في جدول الفئة (class table). يجب أن يتشارك كلا الكائنين نفس الجدول الوهمي (metatable):
local User = {}
User.__index = User
function User:new(id, name)
local instance = {}
setmetatable(instance, self)
instance.id = id
instance.name = name
return instance
end
function User:__eq(other)
return self.id == other.id
endالآن تصبح الكائنات متساوية بناءً على منطقك المخصص:
local u1 = User:new(101, "Alice")
local u2 = User:new(101, "Bob")
local u3 = User:new(202, "Alice")
print(u1 == u2) -- Output: true (نفس المعرف ID)
print(u1 == u3) -- Output: false (معرفات IDs مختلفة)جرّب بنفسك
-- استدعاء وحدة المنتج (Product)
local Product = require('Product')
-- قراءة المدخلات
local sku1 = io.read()
local name1 = io.read()
local sku2 = io.read()
local name2 = io.read()
local sku3 = io.read()
local name3 = io.read()
-- TODO: إنشاء ثلاثة كائنات (instances) من المنتج باستخدام المدخلات
-- TODO: طباعة المعلومات لكل منتج (ثلاثة أسطر)
-- TODO: طباعة نتيجة مقارنة المنتج الأول مع المنتج الثاني
-- TODO: طباعة نتيجة مقارنة المنتج الأول مع المنتج الثالث
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس 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 للابنالمشترك مقابل الفريدملخص - التسلسل الهرمي للأشكال