جدول Singleton
جزء من قسم البرمجة كائنية التوجه في رحلة Lua على Coddy. الدرس 63 من 70.
أحيانًا تحتاج إلى نسخة واحدة بالضبط من شيء ما في برنامجك بأكمله: مدير إعدادات، أو نظام تسجيل، أو إعدادات اللعبة. قد يتسبب إنشاء نسخ متعددة في حدوث مشكلات: أيٌّ منها يحتوي على البيانات الصحيحة؟ يضمن نمط Singleton وجود نسخة واحدة فقط.
في Lua، يُعدّ تنفيذ Singleton أمرًا بسيطًا بشكل مدهش بفضل طريقة عمل الوحدات. عند استخدام require لوحدة، تخزّن Lua النتيجة مؤقتًا. وتُعيد الاستدعاءات اللاحقة لـ require الجدول المخزّن مؤقتًا، وليس جدولًا جديدًا.
-- GameConfig.lua
local GameConfig = {
volume = 80,
difficulty = "normal"
}
function GameConfig:setVolume(v)
self.volume = v
end
return GameConfig
الآن، في أي مكان داخل برنامجك:
local config1 = require("GameConfig")
local config2 = require("GameConfig")
config1:setVolume(50)
print(config2.volume) -- 50 (نفس الجدول!)
يشير كلٌّ من config1 وconfig2 إلى الجدول نفسه تمامًا. وتظهر التغييرات التي تُجرى من خلال أحد المتغيرين من خلال الآخر. يحدث هذا تلقائيًا لأن require في Lua يخزّن القيمة المُعادة في package.loaded ويعيد استخدامها.
على عكس نمط Factory الذي ينشئ كائنات جديدة، يضمن Singleton حالةً مشتركة عبر تطبيقك بالكامل. وهذا مثالي للإعدادات العامة التي تحتاج أجزاء متعددة من التعليمات البرمجية لديك إلى الوصول إليها وتعديلها باستمرار.
التحدي
سهللننشئ مديرًا لإعدادات اللعبة باستخدام نمط Singleton! ستنشئ وحدة تهيئة تضمن وصول كل جزء من برنامجك إلى الإعدادات نفسها تمامًا، بغض النظر عن عدد مرات طلبها.
ستنظم التعليمات البرمجية عبر ملفين:
GameSettings.lua: أنشئ وحدة Singleton تخزّن تهيئة اللعبة. يجب أن يتضمن جدول الإعدادات لديكmusicVolume(يبدأ بقيمة 70)، وsfxVolume(يبدأ بقيمة 100)، وdifficulty(يبدأ بقيمة"normal"). أضف ثلاث طرق::setMusicVolume(value)، و:setSfxVolume(value)، و:setDifficulty(level)لتعديل هذه الإعدادات. تذكّر إعادة الجدول في نهاية الوحدة!main.lua: أثبت أن Singleton يعمل من خلال طلب وحدة GameSettings مرتين داخل متغيرين مختلفين. استخدم المتغير الأول لتغيير مستوى صوت الموسيقى ودرجة الصعوبة. ثم استخدم المتغير الثاني لطباعة الإعدادات الثلاثة. إذا كان Singleton يعمل بشكل صحيح، فسيشير كلا المتغيرين إلى الجدول نفسه، ولذلك ستكون التغييرات التي تُجرى من خلال أحدهما مرئية من خلال الآخر.
ستتلقى مُدخلين:
- مستوى صوت الموسيقى الجديد (رقم)
- مستوى الصعوبة الجديد (سلسلة نصية مثل
"easy"أو"hard")
بعد تعديل الإعدادات من خلال المتغير الأول، اطبع الإعدادات الثلاثة باستخدام المتغير الثاني، كل إعداد في سطر مستقل وبهذا الترتيب: مستوى صوت الموسيقى، ثم مستوى صوت المؤثرات الصوتية، ثم درجة الصعوبة.
على سبيل المثال، إذا كانت المدخلات هي 50 وhard، فيجب أن يكون الناتج:
50
100
hardإذا كانت المدخلات هي 25 وeasy، فيجب أن يكون الناتج:
25
100
easyلاحظ أن مستوى صوت المؤثرات الصوتية يظل بقيمته الافتراضية 100 لأننا لم نغيّره مطلقًا، بينما يعكس مستوى صوت الموسيقى ودرجة الصعوبة التغييرات التي أُجريت من خلال المتغير الأول، مما يثبت أن كلا المتغيرين يشيران إلى مثيل Singleton نفسه!
جرّب بنفسك
-- main.lua - توضيح نمط الـ Singleton
-- قراءة المدخلات
local newMusicVolume = tonumber(io.read())
local newDifficulty = io.read()
-- TODO: استيراد وحدة GameSettings إلى متغير (مثل settings1)
-- TODO: استيراد وحدة GameSettings مرة أخرى إلى متغير مختلف (مثل settings2)
-- (إذا عمل نمط Singleton بشكل صحيح، فإن كلا المتغيرين يشيران إلى نفس الجدول!)
-- TODO: استخدم المتغير الأول لـ:
-- - تعيين مستوى صوت الموسيقى إلى newMusicVolume
-- - تعيين الصعوبة إلى newDifficulty
-- TODO: استخدم المتغير الثاني لطباعة الإعدادات
-- اطبع كلًا منها في سطره الخاص: musicVolume, sfxVolume, difficulty
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس البرمجة كائنية التوجه
4مشروع: بنك رقمي
إعداد المشروعطريقة الإيداع7تعدد الأشكال وإعادة التعريف
إعادة تعريف الدوالاستدعاء دوال الفئة الأبDuck Typingواجهة مشتركةالتحقق من النوعمراجعة - أدوار الموظفين2نمط النموذج الأولي للفئات
مفهوم النموذج الأوليالربط باستخدام __indexالمنشئ :new()تهيئة الخصائصنسخ مستقلةملخص - مصنع السيارات5تحميل المعاملات في OOP
جمع الكائناتطرح الكائناتدمج الكائناتمقارنة الكائنات (<, >)مراجعة - رياضيات المحفظة8التغليف
اصطلاحات التسميةاستخدام Closures للخصوصيةالوصول عبر Closuresجداول للقراءة فقطمنطق التحقق من الصحةمراجعة - الخزنة الآمنة11أنماط التصميم (مبسط)
دوال المصنعجدول Singletonنمط الـ Iteratorالمراقب (المستمع)مراجعة - مصنع الـ Logger3حالة الكائن وسلوكه
متغيرات النسخةدالات الجلب (Getter Methods)دالات التعيين (Setter Methods)الخصائص المحسوبةتنسيق النصوصالتحقق من المساواةمراجعة - درجة الطالب6أساسيات الوراثة
إعداد الوراثةوراثة الـ Methodsتوسيع الـ Constructorإضافة Methods للابنالمشترك مقابل الفريدملخص - التسلسل الهرمي للأشكالتدرّب بنفسك: مترجم Lua عبر الإنترنت