Menu
Coddy logo textTech

גישה באמצעות Closures

חלק מהיחידה תכנות מונחה עצמים במסלול ה-Lua של Coddy. שיעור 45 מתוך 70.

משתנים מקומיים פרטיים חסרי תועלת אם אי אפשר לעולם ליצור איתם אינטראקציה. הפתרון הוא להגדיר מתודות getter ו-setter בתוך הבנאי, שם יש להן גישה לתחום של הסגירה.

מכיוון שהמתודות האלה נוצרות בתוך :new(), הן יכולות "לראות" את המשתנים המקומיים. משייכים אותן ישירות לאובייקט:

local Counter = {}
Counter.__index = Counter

function Counter:new()
    local count = 0  -- משתנה פרטי
    
    local obj = {}
    
    -- הגדר מתודות בתוך הבנאי
    function obj:getCount()
        return count
    end
    
    function obj:increment()
        count = count + 1
    end
    
    setmetatable(obj, Counter)
    return obj
end

כעת אפשר לגשת למשתנה הפרטי count, אבל רק באמצעות המתודות שסיפקת:

local c = Counter:new()
print(c:getCount())  -- 0
c:increment()
c:increment()
print(c:getCount())  -- 2
print(c.count)       -- nil (עדיין מוסתר!)

שימו לב ש-:getCount() ו-:increment() מוגדרות ישירות על obj, ולא על טבלת המחלקה. כל מופע מקבל עותק משלו של הפונקציות האלה, ולכל אחת מהן יש גישה ל-count הפרטי שלה. זהו המחיר של הפשרה: פרטיות אמיתית צורכת מעט יותר זיכרון, מכיוון שהמתודות אינן משותפות דרך אב הטיפוס.

challenge icon

אתגר

קל

בואו נבנה מחלקת Temperature שמשתמשת בפרטיות המבוססת על סגירה כדי לאחסן ערך טמפרטורה במעלות צלזיוס, עם שיטות getter ו-setter שמוגדרות בתוך הבנאי כדי לאפשר גישה מבוקרת!

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

  • Temperature.lua: צור מחלקה שבה ערך הטמפרטורה מאוחסן במשתנה מקומי בתוך הבנאי: מוסתר לחלוטין מגישה מבחוץ. הבנאי :new(initialCelsius) צריך לאחסן את הטמפרטורה במשתנה מקומי, ואז להגדיר את השיטות האלה ישירות במופע האובייקט:
    • :getCelsius(): מחזירה את הטמפרטורה הנוכחית במעלות צלזיוס
    • :setCelsius(value): מעדכנת את הטמפרטורה לערך חדש
    • :getFahrenheit(): מחזירה את הטמפרטורה לאחר המרה למעלות פרנהייט לפי הנוסחה: (celsius * 9/5) + 32
  • main.lua: טען את המודול Temperature וקרא שני ערכים מהקלט: טמפרטורה התחלתית וטמפרטורה חדשה להגדרה. צור מופע של Temperature עם הערך ההתחלתי, הדפס את הקריאות במעלות צלזיוס ובמעלות פרנהייט, ואז השתמש ב-setter כדי לשנות את הטמפרטורה ולהדפיס שוב את שתי הקריאות.

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

  1. הטמפרטורה ההתחלתית במעלות צלזיוס (מספר)
  2. טמפרטורה חדשה להגדרה (מספר)

הפלט שלך צריך לכלול ארבע שורות שמציגות את קריאות הטמפרטורה לפני השינוי ואחריו:

Celsius: {initialValue}
Fahrenheit: {convertedInitial}
Celsius: {newValue}
Fahrenheit: {convertedNew}

לדוגמה, אם הקלטים הם 0 ו-100, הפלט צריך להיות:

Celsius: 0
Fahrenheit: 32
Celsius: 100
Fahrenheit: 212

זכור: יש לאחסן את ערך הטמפרטורה במשתנה מקומי בתוך :new(), ולא בתוך self. שיטות ה-getter וה-setter מוגדרות בתוך הבנאי, שם הן יכולות לגשת למשתנה הפרטי הזה באמצעות סגירה. ניסיון לגשת ישירות אל temp.celsius או אל temp._celsius צריך להחזיר nil!

נסו בעצמכם

-- טען את המודול Temperature באמצעות require
local Temperature = require('Temperature')

-- קרא את ערכי הקלט
local initialTemp = tonumber(io.read())
local newTemp = tonumber(io.read())

-- TODO: צור מופע של Temperature עם הערך ההתחלתי

-- TODO: הדפס את קריאות Celsius ו-Fahrenheit ההתחלתיות

-- TODO: השתמש בפונקציית ה-setter כדי לשנות את הטמפרטורה ל-newTemp

-- TODO: הדפס את קריאות Celsius ו-Fahrenheit המעודכנות
quiz iconבחנו את עצמכם

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

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

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