ממשק משותף
חלק מהיחידה תכנות מונחה עצמים במסלול ה-Lua של Coddy. שיעור 40 מתוך 70.
טיפוס ברווז הראה לנו שמחלקות לא קשורות יכולות לעבוד יחד אם יש להן שמות שיטות משותפים. הרעיון הזה מוביל לתפיסת עיצוב רבת עוצמה: ממשק משותף. כשמתכננים בכוונה כמה מחלקות כך שיהיו להן אותן חתימות של שיטות, יוצרים רכיבים שניתן להחליף ביניהם.
דמיין שאתה בונה מערכת לרישום הודעות. ייתכן שתרצה לשלוח הודעות ליעדים שונים: קובץ, המסך או אפילו רשת. במקום לכתוב קוד נפרד לכל אחד מהם, אתה מתכנן את כל מחלקות הפלט שלך כך שיממשו את אותה השיטה :write():
local LogFile = {}
LogFile.__index = LogFile
function LogFile:new(filename)
local obj = {filename = filename}
setmetatable(obj, LogFile)
return obj
end
function LogFile:write(message)
print("[FILE:" .. self.filename .. "] " .. message)
end
local Screen = {}
Screen.__index = Screen
function Screen:new()
local obj = {}
setmetatable(obj, Screen)
return obj
end
function Screen:write(message)
print("[SCREEN] " .. message)
endעכשיו כל קוד שצריך להציג הודעות יכול לקבל כל אחד משני הסוגים:
local function logMessage(output, msg)
output:write(msg)
end
local file = LogFile:new("app.log")
local screen = Screen:new()
logMessage(file, "Starting up") -- [FILE:app.log] מתחיל לפעול
logMessage(screen, "Starting up") -- [SCREEN] מתחיל לפעולהפונקציה logMessage לא יודעת ולא אכפת לה איזו מחלקה היא מקבלת. היא מצפה רק לשיטה :write(). כך הקוד שלך גמיש. אפשר להוסיף סוגי פלט חדשים בהמשך בלי לשנות פונקציות קיימות.
אתגר
קלבואו נבנה מערכת לעיבוד תשלומים שבה אפשר להשתמש בשיטות תשלום שונות לסירוגין! תיצרו שתי מחלקות תשלום שונות לחלוטין שחולקות ממשק משותף, המתודה :process(amount), כך שכל קוד שמטפל בתשלומים יוכל לעבוד עם כל אחד מהסוגים בלי לדעת מה ההבדל ביניהם.
תארגנו את הקוד שלכם בשלושה קבצים:
CreditCard.lua: מחלקת תשלום עם בנאי:new(cardNumber)ששומר את מספר הכרטיס. המתודה:process(amount)שלה צריכה להדפיסCharging {amount} to card {cardNumber}.BankTransfer.lua: מחלקת תשלום נפרדת לחלוטין עם בנאי:new(accountId). המתודה:process(amount)שלה צריכה להדפיסTransferring {amount} from account {accountId}.main.lua: צרו פונקציה בשםhandlePayment(paymentMethod, amount)שמקבלת כל אובייקט תשלום וסכום, ואז קוראת לו עם:process(amount). הפונקציה הזאת לא צריכה לדעת אם היא עובדת עם כרטיס אשראי או העברה בנקאית. היא רק מצפה שלאובייקט תהיה מתודה:process().
תקבלו שלוש קלטים:
- מספר כרטיס אשראי (לדוגמה,
4532-1234-5678) - מזהה חשבון בנק (לדוגמה,
ACC-9876) - סכום התשלום (לדוגמה,
150)
בקובץ הראשי שלכם, צרו מופע אחד מכל סוג תשלום באמצעות שני הקלטים הראשונים. לאחר מכן, השתמשו בפונקציה handlePayment שלכם כדי לעבד את הסכום הנתון באמצעות שתי שיטות התשלום: תחילה כרטיס האשראי, ואז ההעברה הבנקאית.
לדוגמה, אם הקלטים הם 1111-2222-3333, ACC-5555 ו-75, הפלט צריך להיות:
Charging 75 to card 1111-2222-3333
Transferring 75 from account ACC-5555היתרון בעיצוב הזה הוא שהפונקציה handlePayment שלכם עובדת עם כל אובייקט שמממש את :process(). תוכלו להוסיף מחר מחלקת PayPal, וכל עוד יש לה מתודה :process(amount), היא תעבוד עם הפונקציה הקיימת שלכם בלי שתצטרכו לבצע שינויים!
נסו בעצמכם
-- ייבא את מחלקות התשלום
local CreditCard = require('CreditCard')
local BankTransfer = require('BankTransfer')
-- קרא את הקלטים
local cardNumber = io.read()
local accountId = io.read()
local amount = tonumber(io.read())
-- TODO: צור את הפונקציה handlePayment שמקבלת כל אובייקט תשלום
-- וסכום, ואז קוראת למתודה :process(amount) שלו
-- TODO: צור מופעים של CreditCard ושל BankTransfer באמצעות הקלטים
-- TODO: השתמש ב-handlePayment כדי לעבד את הסכום בשתי שיטות התשלום
-- תחילה בכרטיס האשראי, ואז בהעברה הבנקאית
השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.
כל השיעורים ביחידה תכנות מונחה עצמים
4פרויקט: בנק דיגיטלי
הגדרת הפרויקטפעולת הפקדה7פולימורפיזם ודריסת מתודות
דריסת מתודותקריאה למתודות של מחלקת האבטיפוסיות ברווזממשק משותףבדיקת טיפוססיכום – תפקידי עובדים2תבנית אב־טיפוס למחלקה
מושג אב־הטיפוסקישור באמצעות __indexהבנאי :new()אתחול מאפייניםמופעים עצמאייםסיכום – מפעל מכוניות5העמסת אופרטורים בתכנות מונחה עצמים
חיבור אובייקטיםחיסור אובייקטיםשרשור אובייקטיםהשוואת אובייקטים (<, >)חזרה – חישובים עם ארנק8כימוס
כללי מתן שמותClosures לשמירה על פרטיותגישה באמצעות Closuresטבלאות לקריאה בלבדלוגיקת אימותסיכום – כספת מאובטחת11תבניות עיצוב (בקצרה)
פונקציות Factoryטבלת Singletonתבנית IteratorObserver (מאזין)סיכום – מפעל Logger3מצב והתנהגות של אובייקטים
משתני מופעמתודות Getterמתודות Setterמאפיינים מחושביםעיצוב מחרוזותבדיקות שוויוןסיכום – ציון תלמיד6יסודות הירושה
הכנת מבנה הירושהירושת מתודותהרחבת הבנאיהוספת מתודות למחלקת הבתמשותף לעומת ייחודיסיכום – היררכיית צורותתרגלו בעצמכם: קומפיילר Lua אונליין