גישה באמצעות 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 הפרטי שלה. זהו המחיר של הפשרה: פרטיות אמיתית צורכת מעט יותר זיכרון, מכיוון שהמתודות אינן משותפות דרך אב הטיפוס.
אתגר
קלבואו נבנה מחלקת Temperature שמשתמשת בפרטיות המבוססת על סגירה כדי לאחסן ערך טמפרטורה במעלות צלזיוס, עם שיטות getter ו-setter שמוגדרות בתוך הבנאי כדי לאפשר גישה מבוקרת!
תארגן את הקוד שלך בשני קבצים:
Temperature.lua: צור מחלקה שבה ערך הטמפרטורה מאוחסן במשתנה מקומי בתוך הבנאי: מוסתר לחלוטין מגישה מבחוץ. הבנאי:new(initialCelsius)צריך לאחסן את הטמפרטורה במשתנה מקומי, ואז להגדיר את השיטות האלה ישירות במופע האובייקט::getCelsius(): מחזירה את הטמפרטורה הנוכחית במעלות צלזיוס:setCelsius(value): מעדכנת את הטמפרטורה לערך חדש:getFahrenheit(): מחזירה את הטמפרטורה לאחר המרה למעלות פרנהייט לפי הנוסחה:(celsius * 9/5) + 32
main.lua: טען את המודול Temperature וקרא שני ערכים מהקלט: טמפרטורה התחלתית וטמפרטורה חדשה להגדרה. צור מופע של Temperature עם הערך ההתחלתי, הדפס את הקריאות במעלות צלזיוס ובמעלות פרנהייט, ואז השתמש ב-setter כדי לשנות את הטמפרטורה ולהדפיס שוב את שתי הקריאות.
תקבל שני קלטים:
- הטמפרטורה ההתחלתית במעלות צלזיוס (מספר)
- טמפרטורה חדשה להגדרה (מספר)
הפלט שלך צריך לכלול ארבע שורות שמציגות את קריאות הטמפרטורה לפני השינוי ואחריו:
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 המעודכנות
השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.
כל השיעורים ביחידה תכנות מונחה עצמים
4פרויקט: בנק דיגיטלי
הגדרת הפרויקטפעולת הפקדה7פולימורפיזם ודריסת מתודות
דריסת מתודותקריאה למתודות של מחלקת האבטיפוסיות ברווזממשק משותףבדיקת טיפוססיכום – תפקידי עובדים2תבנית אב־טיפוס למחלקה
מושג אב־הטיפוסקישור באמצעות __indexהבנאי :new()אתחול מאפייניםמופעים עצמאייםסיכום – מפעל מכוניות5העמסת אופרטורים בתכנות מונחה עצמים
חיבור אובייקטיםחיסור אובייקטיםשרשור אובייקטיםהשוואת אובייקטים (<, >)חזרה – חישובים עם ארנק8כימוס
כללי מתן שמותClosures לשמירה על פרטיותגישה באמצעות Closuresטבלאות לקריאה בלבדלוגיקת אימותסיכום – כספת מאובטחת11תבניות עיצוב (בקצרה)
פונקציות Factoryטבלת Singletonתבנית IteratorObserver (מאזין)סיכום – מפעל Logger3מצב והתנהגות של אובייקטים
משתני מופעמתודות Getterמתודות Setterמאפיינים מחושביםעיצוב מחרוזותבדיקות שוויוןסיכום – ציון תלמיד6יסודות הירושה
הכנת מבנה הירושהירושת מתודותהרחבת הבנאיהוספת מתודות למחלקת הבתמשותף לעומת ייחודיסיכום – היררכיית צורותתרגלו בעצמכם: קומפיילר Lua אונליין