Menu
Coddy logo textTech

טבלת 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 מבטיח מצב משותף בכל היישום שלך. הדבר אידיאלי להגדרות גלובליות שחלקים שונים בקוד שלך צריכים לגשת אליהן ולשנות אותן באופן עקבי.

challenge icon

אתגר

קל

בואו נבנה מנהל הגדרות למשחק באמצעות תבנית Singleton! תיצרו מודול הגדרות שמבטיח שכל חלק בתוכנית שלכם ניגש לאותן הגדרות בדיוק, בלי קשר למספר הפעמים שבהן הוא נדרש.

תארגנו את הקוד שלכם בשני קבצים:

  • GameSettings.lua: צרו מודול Singleton ששומר את הגדרות המשחק. טבלת ההגדרות שלכם צריכה לכלול את musicVolume (מתחיל ב־70), את sfxVolume (מתחיל ב־100) ואת difficulty (מתחיל ב־"normal"). הוסיפו שלוש מתודות: :setMusicVolume(value), :setSfxVolume(value) ו־:setDifficulty(level) כדי לשנות את ההגדרות האלה. זכרו להחזיר את הטבלה בסוף המודול!
  • main.lua: הדגימו ש־Singleton פועל באמצעות דרישה של מודול GameSettings פעמיים לתוך משתנים שונים. השתמשו במשתנה הראשון כדי לשנות את עוצמת המוזיקה ואת רמת הקושי. לאחר מכן השתמשו במשתנה השני כדי להדפיס את כל שלוש ההגדרות. אם Singleton פועל כראוי, שני המשתנים מפנים לאותה טבלה, ולכן שינויים שנעשים באמצעות אחד מהם גלויים גם באמצעות האחר.

תקבלו שתי קלטים:

  1. עוצמת מוזיקה חדשה (מספר)
  2. רמת קושי חדשה (מחרוזת כמו "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
quiz iconבחנו את עצמכם

השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.

כל השיעורים ביחידה תכנות מונחה עצמים

תרגלו בעצמכם: קומפיילר Lua אונליין