קידום מתודות
חלק מהיחידה תכנות מונחה עצמים במסלול ה-GO של Coddy. שיעור 36 מתוך 107.
כשם שהטמעת struct מקדמת שדות אל ה־struct החיצוני, Go מקדמת גם מתודות מטיפוסים מוטמעים. פירוש הדבר הוא שאפשר לקרוא למתודות שהוגדרו ב־struct המוטמע ישירות על ה־struct החיצוני.
type Engine struct {
Horsepower int
}
func (e Engine) Start() string {
return "Engine started"
}
type Car struct {
Model string
Engine // מוטמע
}
מכיוון ש־Car מכיל את Engine, המתודה Start() מקודמת אוטומטית:
func main() {
c := Car{
Model: "Sedan",
Engine: Engine{Horsepower: 200},
}
fmt.Println(c.Start()) // המנוע הופעל
fmt.Println(c.Engine.Start()) // גם עובד
}
לקידום הזה יש השלכה חשובה על ממשקים. אם הטיפוס המוכלל מממש ממשק, גם הטיפוס החיצוני מממש אותו באופן אוטומטי:
type Starter interface {
Start() string
}
func Ignite(s Starter) {
fmt.Println(s.Start())
}
func main() {
c := Car{Model: "Sedan", Engine: Engine{Horsepower: 200}}
Ignite(c) // Car מממשת את Starter באמצעות Engine
}
הטיפוס Car לעולם אינו מממש במפורש את Starter, אך הוא עומד בדרישות הממשק משום של-Engine המשולב בו יש את המתודה הנדרשת. כך Go מאפשרת שימוש חוזר בהתנהגות ללא ירושה מסורתית.
אתגר
קלבואו נבנה מערכת נגן מוזיקה המדגימה כיצד שיטות של טיפוסים מוטמעים מקודמות לטיפוס החיצוני, וכיצד הדבר מאפשר עמידה בדרישות של ממשק באמצעות הרכבה.
תארגנו את הקוד שלכם בשני קבצים:
audio.go: צרו את אבני הבניין של נגן המוזיקה שלכם:- מבנה
AudioPlayerעם שדהBrand(מחרוזת) ושיטהPlay() stringשמחזירה[Brand] playing audio - ממשק
Playableשדורש שיטהPlay() string - מבנה
Smartphoneעם שדהModelשמטמיע אתAudioPlayer - מבנה
Tabletעם שדהModelשמטמיע אתAudioPlayer
- מבנה
main.go: צרו פונקציה בשםStartPlaybackשמקבלת כל ערך שמקיים את הממשקPlayableומחזירה את התוצאה של קריאה ל־Play(). קראו את פרטי המכשירים מהקלט, צרו גםSmartphoneוגםTablet, והדגימו ששניהם מקיימים את הממשקPlayableבאמצעותAudioPlayerהמוטמע בהם, אף על פי שאף אחד מהטיפוסים אינו מממש בעצמו אתPlay()במפורש.
הקלט הבא יסופק:
- שורה 1: שם דגם הסמארטפון
- שורה 2: מותג מערכת השמע של הסמארטפון
- שורה 3: שם דגם הטאבלט
- שורה 4: מותג מערכת השמע של הטאבלט
עבור כל מכשיר, הדפיסו את הדגם שלו ולאחריו את התוצאה של העברתו אל StartPlayback.
לדוגמה, בהינתן iPhone 15, Apple Audio, iPad Pro ו־Beats, הפלט שלכם אמור להיות:
iPhone 15
Apple Audio playing audio
iPad Pro
Beats playing audioשימו לב שאפשר להעביר גם את Smartphone וגם את Tablet אל StartPlayback, מכיוון שהשיטה Play() של AudioPlayer מקודמת אוטומטית לכל אחד מהטיפוסים החיצוניים, וכך הם מקיימים את הממשק Playable ללא צורך בקוד נוסף.
נסו בעצמכם
package main
import (
"bufio"
"fmt"
"os"
)
// TODO: צרו פונקציה בשם StartPlayback שמקבלת כל ערך מסוג Playable
// ומחזירה את התוצאה של הקריאה ל-Play()
func main() {
scanner := bufio.NewScanner(os.Stdin)
// קראו את דגם הסמארטפון
scanner.Scan()
smartphoneModel := scanner.Text()
// קראו את מותג השמע של הסמארטפון
scanner.Scan()
smartphoneBrand := scanner.Text()
// קראו את דגם הטאבלט
scanner.Scan()
tabletModel := scanner.Text()
// קראו את מותג השמע של הטאבלט
scanner.Scan()
tabletBrand := scanner.Text()
// TODO: צרו Smartphone עם AudioPlayer מוטמע
// TODO: צרו Tablet עם AudioPlayer מוטמע
// TODO: הדפיסו את דגם הסמארטפון, ואז קראו ל-StartPlayback עם הסמארטפון
// TODO: הדפיסו את דגם הטאבלט, ואז קראו ל-StartPlayback עם הטאבלט
_ = smartphoneModel
_ = smartphoneBrand
_ = tabletModel
_ = tabletBrand
fmt.Println("TODO: Complete the implementation")
}
השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.
כל השיעורים ביחידה תכנות מונחה עצמים
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 אונליין