Menu
Coddy logo textTech

טיפוסיות ברווז

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

Lua לא מתעניינת במחלקה של אובייקט. אכפת לה רק ממה שהאובייקט יכול לעשות. המושג הזה נקרא טיפוס ברווז: "אם הוא הולך כמו ברווז ומגעגע כמו ברווז, הוא ברווז." במונחי תכנות, אם יש לאובייקט המתודה שאת קוראת לה, היא עובדת.

המשמעות היא שאפשר להשתמש יחד במחלקות שאינן קשורות כלל, כל עוד יש להן שם מתודה משותף:

local Circle = {}
Circle.__index = Circle
function Circle:new() 
    local obj = {}
    setmetatable(obj, Circle)
    return obj
end
function Circle:draw()
    print("Drawing a circle")
end

local Square = {}
Square.__index = Square
function Square:new()
    local obj = {}
    setmetatable(obj, Square)
    return obj
end
function Square:draw()
    print("Drawing a square")
end

למחלקות האלה אין קשר של ירושה: הן עצמאיות לחלוטין. ובכל זאת, אפשר להתייחס אליהן באופן זהה:

local shapes = {Circle:new(), Square:new(), Circle:new()}

for _, shape in ipairs(shapes) do
    shape:draw()
end
-- פלט:
-- מציירים עיגול
-- מציירים ריבוע
-- מציירים עיגול

הלולאה לא בודקת מהו הטיפוס של כל אובייקט. היא פשוט קוראת ל־:draw() וסומכת על כך שהמתודה קיימת. הגמישות הזאת עוצמתית. אפשר להוסיף סוגים חדשים של צורות בלי לשנות כלל את קוד הלולאה. כל עוד המחלקה החדשה מממשת את :draw(), זה פשוט עובד.

challenge icon

אתגר

קל

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

תיצרו שלוש מחלקות התראות עצמאיות, שאף אחת מהן לא יורשת מהאחרות, אבל כולן מממשות מתודה :send(). המשמעות היא שתוכלו לעבור בלולאה על אוסף מעורב ולקרוא ל־:send() בכל אחת מהן בלי להתחשב בסוג שלה בפועל.

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

  • Email.lua: מחלקה עם בנאי :new(recipient) ששומרת למי נשלח האימייל. המתודה :send() שלה צריכה להדפיס Emailing {recipient}.
  • SMS.lua: מחלקה נפרדת לחלוטין עם בנאי :new(phoneNumber). המתודה :send() שלה צריכה להדפיס Texting {phoneNumber}.
  • PushNotification.lua: מחלקה עצמאית נוספת עם בנאי :new(deviceId). המתודה :send() שלה צריכה להדפיס Pushing to {deviceId}.
  • main.lua: חברו את הכול יחד! קראו שלושה קלטים, צרו מופע אחד מכל סוג של התראה, הכניסו את כולם לטבלה אחת, ואז עברו עליהם בלולאה וקראו ל־:send() בכל אחד מהם.

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

  1. נמען של אימייל (למשל, alice@example.com)
  2. מספר טלפון (למשל, 555-1234)
  3. מזהה מכשיר (למשל, device_99)

בקובץ הראשי שלכם, צרו את כל שלושת אובייקטי ההתראה, שמרו אותם בטבלה ועברו על הטבלה תוך קריאה ל־:send() בכל אחד מהם. הסדר צריך להיות: תחילה Email, אחר כך SMS, ואז PushNotification.

לדוגמה, אם הקלטים הם bob@mail.com, 555-9876 ו־phone_42, הפלט צריך להיות:

Emailing bob@mail.com
Texting 555-9876
Pushing to phone_42

שימו לב שהלולאה שלכם לא צריכה לבדוק מהו הסוג של כל אובייקט. היא פשוט סומכת על כך שלכל אובייקט באוסף יש מתודה :send(). זאת דוגמה לטיפוס ברווז בפעולה! אם הוא יכול לבצע :send(), הוא התראה.

נסו בעצמכם

-- main.lua
-- רכזו את כל סוגי ההתראות והדגימו טיפוס ברווזי

-- ייבאו את המחלקות של ההתראות
local Email = require('Email')
local SMS = require('SMS')
local PushNotification = require('PushNotification')

-- קראו את הקלטים
local recipient = io.read()
local phoneNumber = io.read()
local deviceId = io.read()

-- TODO: צרו מופע אחד מכל סוג התראה

-- TODO: הכניסו את כל ההתראות לטבלה אחת (קודם Email, אחר כך SMS, ואז PushNotification)

-- TODO: עברו על הטבלה בלולאה וקראו ל־:send() עבור כל התראה
-- כך מדגימים טיפוס ברווזי – לא בודקים את הסוג, אלא פשוט קוראים ל־:send()
quiz iconבחנו את עצמכם

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

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

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