ממשק משותף
חלק מהיחידה תכנות מונחה עצמים במסלול ה-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] Starting up
logMessage(screen, "Starting up") -- [SCREEN] Starting upלפונקציה 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 אונליין