Menu
Coddy logo textTech

הטמעת כמה Structs

חלק מהיחידה תכנות מונחה עצמים במסלול ה-GO של Coddy. שיעור 37 מתוך 107.

Go מאפשרת לך לשלב כמה מבנים בתוך מבנה יחיד, וכך לשלב התנהגויות ממקורות שונים. הדבר דומה לירושה מרובה בשפות אחרות, אך משתמש בגישת ההרכבה של Go.

type Logger struct{}

func (l Logger) Log(msg string) string {
    return "LOG: " + msg
}

type Notifier struct{}

func (n Notifier) Notify(msg string) string {
    return "NOTIFY: " + msg
}

type Service struct {
    Name string
    Logger
    Notifier
}

למבנה Service יש עכשיו גישה למתודות של שני הטיפוסים המוטמעים:

func main() {
    s := Service{Name: "OrderService"}
    fmt.Println(s.Log("started"))      // LOG: started
    fmt.Println(s.Notify("new order")) // NOTIFY: new order
}

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

type A struct{}
func (A) Greet() string { return "Hello from A" }

type B struct{}
func (B) Greet() string { return "Hello from B" }

type Combined struct {
    A
    B
}

func main() {
    c := Combined{}
    // c.Greet() - שגיאת קומפילציה: בורר דו־משמעי
    fmt.Println(c.A.Greet())  // שלום מ־A
    fmt.Println(c.B.Greet())  // שלום מ־B
}

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

challenge icon

אתגר

קל

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

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

  • controllers.go: צרו שתי structs עצמאיות של בקרים, המספקות יכולות שונות:
    • LightController עם שדה Brightness מסוג (int) ומתודה SetLight(level int) string שמחזירה Light set to [level]%
    • AudioController עם שדה Volume מסוג (int) ומתודה SetVolume(level int) string שמחזירה Volume set to [level]%
    לשני הבקרים צריכה להיות גם מתודה Status() string. כך נוצר מצב של התנגשות שמות שתצטרכו לטפל בו. LightController.Status() צריכה להחזיר Brightness: [Brightness]%, ו-AudioController.Status() צריכה להחזיר Volume: [Volume]%.
  • device.go: צרו struct בשם SmartDevice עם שדה Name, המטמיעה גם את LightController וגם את AudioController. הוסיפו מתודה בשם FullStatus() string שמחזירה את שם המכשיר יחד עם הסטטוסים של שני הבקרים, ופותרת את העמימות באמצעות קריאה מפורשת למתודת Status() של כל טיפוס מוטמע.
  • main.go: קראו את תצורת המכשיר מהקלט, צרו SmartDevice, השתמשו במתודות המקודמות כדי להגדיר את רמות התאורה ועוצמת הקול, ואז הציגו את הסטטוס המלא.

הקלט הבא יסופק:

  • שורה 1: שם המכשיר
  • שורה 2: רמת הבהירות ההתחלתית (מספר שלם)
  • שורה 3: עוצמת הקול ההתחלתית (מספר שלם)
  • שורה 4: רמת הבהירות החדשה להגדרה (מספר שלם)
  • שורה 5: עוצמת הקול החדשה להגדרה (מספר שלם)

המתודה FullStatus() שלכם צריכה להחזיר:

[Name] - [LightController.Status()], [AudioController.Status()]

הדפיסו את התוצאות של הקריאות ל-SetLight ול-SetVolume (המקודמות מהטיפוסים המוטמעים), ואז הדפיסו את הסטטוס המלא.

לדוגמה, עבור Living Room Hub, 50, 30, 75 ו-60, הפלט שלכם צריך להיות:

Light set to 75%
Volume set to 60%
Living Room Hub - Brightness: 75%, Volume: 60%

שימו לב שאפשר לגשת ישירות ל-SetLight ול-SetVolume דרך SmartDevice באמצעות קידום מתודות, אבל Status() דורשת ציון מפורש של הטיפוס, משום שלשני הטיפוסים המוטמעים יש מתודה בשם זה.

נסו בעצמכם

package main

import (
	"fmt"
)

func main() {
	// קרא את הקלט
	var name string
	fmt.Scanln(&name)

	var initialBrightness int
	fmt.Scanln(&initialBrightness)

	var initialVolume int
	fmt.Scanln(&initialVolume)

	var newBrightness int
	fmt.Scanln(&newBrightness)

	var newVolume int
	fmt.Scanln(&newVolume)

	// TODO: צור SmartDevice עם השם והערכים ההתחלתיים הנתונים

	// TODO: השתמש במתודה SetLight שקודמה והדפס את התוצאה

	// TODO: השתמש במתודה SetVolume שקודמה והדפס את התוצאה

	// TODO: הדפס את המצב המלא באמצעות המתודה FullStatus()
}
quiz iconבחנו את עצמכם

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

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

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