Menu
Coddy logo textTech

מיקסינים לעומת ירושה

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

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

השתמשו בירושה כשלאובייקטים יש זהות בסיסית משותפת. Bird הוא Animal. הגיוני ש-Bird יירש התנהגויות בסיסיות של בעלי חיים, כמו :eat() או :sleep(). הקשר הוא קבוע ומגדיר מהו האובייקט במהותו.

השתמשו בmixins כשרוצים להוסיף יכולת שאינה מגדירה את הזהות המרכזית של האובייקט.

לא כל הציפורים יכולות לעוף: פינגווינים ויענים הם ציפורים, אבל הם לא עפים. תעופה היא יכולת, לא תכונה שמגדירה ציפור. מיקסין Flyable מאפשר להוסיף יכולת תעופה לציפורים שזקוקות לה, בלי לכפות אותה על כולן.

שתי הגישות עובדות נהדר יחד:

-- Bird יורשת מ-Animal (יחס של "הוא סוג של")
local Bird = {}
Bird.__index = Bird
setmetatable(Bird, {__index = Animal})

-- Flyable היא יכולת (mixin)
local Flyable = {}
function Flyable:fly()
    print(self.name .. " soars through the sky!")
end

-- החילו את ה-mixin רק על ציפורים שיכולות לעוף
applyMixin(Bird, Flyable)

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

challenge icon

אתגר

קל

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

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

  • Animal.lua: צרו את מחלקת הבסיס Animal עם בנאי :new(name) ששומר את השם. כללו מתודה :eat() שמדפיסה {name} is eating. זה מייצג את הזהות הבסיסית המשותפת לכל בעלי החיים.
  • Swimmable.lua: צרו מיקסין עם מתודה :swim() שמדפיסה {self.name} is swimming. זוהי יכולת, ולא כל היצורים יכולים לשחות, לכן היא לא אמורה להיות חלק משרשרת הירושה.
  • Bird.lua: צרו מחלקת Bird שיורשת מ-Animal. הבנאי :new(name, canSwim) צריך לקרוא לבנאי של מחלקת האב ולשמור אם הציפור הזאת יכולה לשחות. החילו את המיקסין Swimmable על מחלקת Bird. כללו מתודה :chirp() שמדפיסה {name} chirps!. זוהי התנהגות ייחודית לציפורים.
  • main.lua: כתבו כאן את פונקציית העזר applyMixin. קראו את הקלטים עבור שם הציפור ואם היא יכולה לשחות (yes או no). צרו מופע של Bird, ואז הדגימו את היכולות שלו: קראו ל-:eat() (שעוברת בירושה מ-Animal), קראו ל-:chirp() (המתודה של Bird), וקראו ל-:swim() רק אם הציפור יכולה לשחות.

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

  1. שם הציפור (מחרוזת)
  2. האם הציפור יכולה לשחות: yes או no

אם הציפור יכולה לשחות, הפלט שלכם צריך להיות:

{name} is eating
{name} chirps!
{name} is swimming

אם הציפור לא יכולה לשחות, הפלט שלכם צריך להיות:

{name} is eating
{name} chirps!

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

Duck is eating
Duck chirps!
Duck is swimming

אם הקלטים הם Sparrow ו-no, הפלט צריך להיות:

Sparrow is eating
Sparrow chirps!

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

נסו בעצמכם

-- main.lua: נקודת כניסה - צרו ציפור והדגימו את יכולותיה

-- פונקציית עזר להחלת mixin על מחלקה
local function applyMixin(class, mixin)
    -- TODO: העתיקו את כל המתודות מ-mixin למחלקה
    
end

-- החילו את ה-mixin Swimmable על Bird לפני טעינת Bird באמצעות require
-- הערה: ייתכן שתצטרכו לטפל בכך ב-Bird.lua או כאן

local Bird = require('Bird')
local Swimmable = require('Swimmable')

-- החילו את ה-mixin על המחלקה Bird
applyMixin(Bird, Swimmable)

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

-- TODO: קבעו אם הציפור יכולה לשחות לפי הקלט ("yes" או "no")

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

-- TODO: קראו ל-eat() - מתודה שעברה בירושה מ-Animal

-- TODO: קראו ל-chirp() - מתודה של Bird עצמה

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

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

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

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