הסתרת מתודות מוטמעות
חלק מהיחידה תכנות מונחה עצמים במסלול ה-GO של Coddy. שיעור 39 מתוך 107.
לפעמים צריך שהמבנה החיצוני יספק מימוש משלו למתודה שכבר קיימת בסוג המוטמע. הדבר נקרא הסתרה, והוא מאפשר לדרוס מתודות שקודמו עם התנהגות מותאמת אישית.
כשמגדירים מתודה במבנה החיצוני בעלת שם זהה לזה של מתודה מוטמעת, המתודה החיצונית מקבלת עדיפות:
type Animal struct {
Name string
}
func (a Animal) Speak() string {
return "Some sound"
}
type Dog struct {
Animal
Breed string
}
func (d Dog) Speak() string {
return "Woof!"
}
כעת, כשאתה קורא ל־Speak() על Dog, נעשה שימוש במתודה החיצונית:
func main() {
d := Dog{Animal: Animal{Name: "Rex"}, Breed: "Labrador"}
fmt.Println(d.Speak()) // Woof! - המתודה של Dog
fmt.Println(d.Animal.Speak()) // Some sound - המתודה של Animal
}
השיטה המוטמעת לא נעלמה. עדיין אפשר לגשת אליה במפורש באמצעות שם הטיפוס המוטמע. התבנית הזאת שימושית כשאתם רוצים להתאים אישית את ההתנהגות ובו בזמן להשאיר את המימוש המקורי זמין, אולי כדי לקרוא לו מתוך השיטה שלכם שדורסת אותו:
func (d Dog) Speak() string {
return d.Animal.Speak() + " (but actually Woof!)"
}
הסתרה מאפשרת לך לשלוט באיזו התנהגות נחשפים, תוך שמירה על גישה למקור באמצעות ציון מפורש.
אתגר
קלבואו נבנה מערכת התראות שבה ערוצי התראות שונים יכולים להתאים אישית את אופן העיצוב והשליחה של הודעות. תשתמשו בהצללת מתודות כדי לאפשר לערוצים מסוימים לדרוס את התנהגות ברירת המחדל, ובכל זאת לגשת למימוש המקורי כשצריך.
תארגנו את הקוד שלכם בשלושה קבצים:
base.go: צרו struct בשםBaseNotificationעם השדותTitleו-Priority(שניהם מחרוזות). הוסיפו לו מתודה בשםFormat() stringשמחזירה את ההתראה בפורמט אחיד:[Priority] Title.channels.go: צרו שני סוגים של ערוצי התראות שמטמיעים אתBaseNotificationומצלילים את המתודהFormatבאמצעות מימושים משלהם:EmailNotificationעם שדהRecipient. המתודהFormat()שלה צריכה להחזירEmail to [Recipient]: [Priority] TitleSlackNotificationעם שדהChannel. המתודהFormat()שלה צריכה לקרוא למתודה המוטמעתBaseNotification.Format()ולהוסיף לפני התוצאה את#[Channel]:
main.go: קראו את פרטי ההתראות מהקלט, צרו את שני סוגי ההתראות והדגימו הצללה באמצעות הדפסה של:- הפלט המעוצב של
EmailNotification(באמצעות המתודה המוצללת שלו) - פורמט הבסיס של
EmailNotification(באמצעות קריאה מפורשת למתודה המוטמעת) - הפלט המעוצב של
SlackNotification(שמשתמשת פנימית במתודת הבסיס)
- הפלט המעוצב של
הקלט שיסופק יהיה:
- שורה 1: כותרת ההתראה
- שורה 2: רמת העדיפות
- שורה 3: נמען האימייל
- שורה 4: שם ערוץ Slack
לדוגמה, עבור Server Alert, HIGH, admin@company.com ו-ops-alerts, הפלט שלכם צריך להיות:
Email to admin@company.com: HIGH Server Alert
[HIGH] Server Alert
#ops-alerts: [HIGH] Server Alertשימו לב ש-EmailNotification מחליפה לחלוטין את עיצוב הבסיס, ואילו SlackNotification משפרת אותו באמצעות קריאה למתודה המקורית והוספת הקשר של הערוץ. שתי הגישות מדגימות דרכים שונות להשתמש בהצללת מתודות ביעילות.
נסו בעצמכם
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
scanner := bufio.NewScanner(os.Stdin)
// קרא את כותרת ההתראה
scanner.Scan()
title := scanner.Text()
// קרא את רמת העדיפות
scanner.Scan()
priority := scanner.Text()
// קרא את נמען הדוא״ל
scanner.Scan()
recipient := scanner.Text()
// קרא את שם הערוץ ב-Slack
scanner.Scan()
channel := scanner.Text()
// TODO: צור EmailNotification עם התראת הבסיס, הכותרת, העדיפות והנמען
// TODO: צור SlackNotification עם התראת הבסיס, הכותרת, העדיפות והערוץ
// TODO: הדפס את הפלט המעוצב של EmailNotification (באמצעות המתודה שלו שמסתירה את מתודת הבסיס)
// TODO: הדפס את פורמט הבסיס של EmailNotification (באמצעות קריאה מפורשת למתודה המוטמעת)
// TODO: הדפס את הפלט המעוצב של SlackNotification
fmt.Println() // מציין מקום - הסר בעת המימוש
}
השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.
כל השיעורים ביחידה תכנות מונחה עצמים
1יסודות OOP ב-Go
קבצים חיצונייםסביבת העבודה והמודולים של Goחבילות וייבואשמות מיוצאים לעומת שמות לא מיוצאיםמבוא ל-OOP ב-GoStructs כמחלקותהגדרת מתודות עבור Structsמקבלי Pointer לעומת Valueאתחול Structפונקציות Constructorחזרה – מחשבון פשוט4ממשקים
מבוא לממשקיםמימוש משתמעממשק כחוזהממשק ריק (any)אימות טיפוסמתג טיפוסיםהרכבת ממשקיםממשקי Stringer ו-Errorסיכום – מחשבון צורות7כימוס
שדות מיוצאים לעומת שדות לא מיוצאיםכימוס ברמת החבילהמתודות Getter ו-Setterהסתרת מידע ב-Goסיכום – רשומות תלמידים10Generics (Go 1.18 ומעלה)
מבוא ל־Genericsפרמטרים של טיפוסיםאילוצי טיפוסיםמבנים גנרייםפתרון עוקף למתודות גנריותסיכום – אוסף גנרי2העמקה בסוגים וב-Structs
סוגים בסיסיים ומורכביםהגדרות של סוגים מותאמים אישיתתגיות StructStructs אנונימייםStructs מקונניםערכי אפס וברירות מחדלסיכום – ספר אנשי קשר5קומפוזיציה במקום ירושה
למה ב-Go אין ירושהיסודות הטמעת Structקידום מתודותהטמעת כמה Structsהטמעה לעומת אגרגציההסתרת מתודות מוטמעותסיכום – היררכיית עובדים8טיפול בשגיאות ו-OOP
ממשק errorסוגי שגיאות מותאמים אישיתעטיפת שגיאות (fmt.Errorf)שגיאות Sentinelerrors.Is() ו-errors.As()Panic, Defer ו-Recoverסיכום – מנתח קבצים11ספרייה סטנדרטית ותכנות מונחה עצמים
io.Reader ו-io.Writersort.Interfaceהממשק fmt.Stringerencoding/json עם מבניםהממשק http.Handlerסיכום – מודלים של REST API3מצביעים וזיכרון
יסודות המצביעים ב-Goמצביעים למבניםהעברה לפי ערך לעומת לפי הפניההפונקציה new()איסוף אשפה ב-Goסיכום - בונה רשימה מקושרת6פולימורפיזם ב-Go
פולימורפיזם באמצעות ממשקיםטיפוס ברווז ב-Goכללי התאמה לממשקאוספים פולימורפייםהזרקת תלויותסיכום - מעבד תשלומים9מקביליות ו-OOP
יסודות GoroutinesChannels ותקשורתChannel עם חוצץ לעומת ללא חוצץפקודת Selectsync.Mutex ו-sync.RWMutexsync.WaitGroupתכנון Struct בטוח לשימוש במקבילסיכום - מאגר עובדים12מושגים מתקדמים בתכנות מונחה עצמים
דפוס האפשרויות הפונקציונליותדפוס Builder ב-Goשרשור מתודותכינויי טיפוסים לעומת הגדרותיסודות Reflectionסקירה כללית של יצירת קודתרגלו בעצמכם: קומפיילר Go אונליין