Menu
Coddy logo textTech

הרחבת הבנאי

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

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

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

local Vehicle = {}
Vehicle.__index = Vehicle

function Vehicle:new(speed)
    local obj = {speed = speed}
    setmetatable(obj, Vehicle)
    return obj
end

-- Car יורשת מ-Vehicle
local Car = {}
Car.__index = Car
setmetatable(Car, {__index = Vehicle})

function Car:new(speed, brand)
    local obj = Vehicle.new(Vehicle, speed)  -- קראו לבנאי של מחלקת האב
    obj.brand = brand                         -- הוסיפו שדה ייחודי למחלקת הבת
    setmetatable(obj, Car)                    -- קשרו מחדש ל-Car
    return obj
end

שימו לב לשלבים העיקריים בבנאי של המחלקה הצאצאית: ראשית, אנו קוראים ל־Vehicle.new(Vehicle, speed) כדי לקבל אובייקט שהשדה speed כבר מוגדר בו. לאחר מכן נוסיף את השדה brand הייחודי למחלקה הצאצאית. לבסוף, נשנה את המטא־טבלה מ־Vehicle ל־Car כדי שהמופע יחפש מתודות במחלקה הצאצאית תחילה.

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

local myCar = Car:new(120, "Toyota")
print(myCar.speed)  -- פלט: 120
print(myCar.brand)  -- פלט: Toyota

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

challenge icon

אתגר

קל

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

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

  • Animal.lua: הגדירו את מחלקת האב שלכם עם בנאי :new(name) ששומר את שם החיה. כללו מתודה :describe() שמדפיסה את שם החיה. הגדירו את תבנית המחלקה המקובלת באמצעות __index והחזירו את המחלקה.
  • Bird.lua: הגדירו את מחלקת הבן שיורשת מ־Animal. הבנאי :new(name, wingspan) של Bird צריך לקרוא לבנאי האב באמצעות Animal.new(Animal, name) כדי לאתחל את השם, ואז להוסיף את השדה wingspan לאובייקט, ולבסוף לקשר מחדש את המטא־טבלה ל־Bird. כללו מתודה :info() שמדפיסה גם את השם וגם את מוטת הכנפיים בפורמט מסוים.
  • main.lua: ייבאו את המודול Bird, קראו שני קלטים (שם ומוטת כנפיים), צרו מופע של Bird וקראו לשתי המתודות כדי להדגים שהפונקציונליות שעוברת בירושה והפונקציונליות הייחודית למחלקת הבן פועלות יחד.

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

  1. שם הציפור
  2. מוטת הכנפיים של הציפור (מספר)

בקובץ הראשי שלכם, צרו Bird עם השם ומוטת הכנפיים הנתונים. לאחר מכן קראו ל־:describe() ואחריו ל־:info() בשורות נפרדות.

המתודה :describe() (שעוברת בירושה מ־Animal) צריכה להדפיס:

Animal: {name}

המתודה :info() (המוגדרת ב־Bird) צריכה להדפיס:

{name} has a wingspan of {wingspan}

לדוגמה, אם הקלטים הם Eagle ו־200, הפלט צריך להיות:

Animal: Eagle
Eagle has a wingspan of 200

הנקודה החשובה היא שהבנאי של Bird לא משכפל את אתחול השם. הוא מעביר את המשימה הזאת לבנאי של Animal, ואז מוסיף רק את מה שייחודי לציפורים. כך הקוד שלכם נשאר DRY, ובמקביל נבנית שרשרת ירושה תקינה!

נסו בעצמכם

-- main.lua: נקודת הכניסה

local Bird = require('Bird')

-- קריאת הקלטים
local name = io.read()
local wingspan = tonumber(io.read())

-- TODO: צרו מופע של Bird עם השם ומוטת הכנפיים הנתונים

-- TODO: קראו ל־:describe() על הציפור (מתודה שירשה מ־Animal)

-- TODO: קראו ל־:info() על הציפור (מתודה שמוגדרת ב־Bird)
quiz iconבחנו את עצמכם

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

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

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