Menu
Coddy logo textTech

אוספים פולימורפיים

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

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

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

type Shape interface {
    Area() float64
}

type Circle struct{ Radius float64 }
func (c Circle) Area() float64 { return 3.14159 * c.Radius * c.Radius }

type Rectangle struct{ Width, Height float64 }
func (r Rectangle) Area() float64 { return r.Width * r.Height }

func main() {
    shapes := []Shape{
        Circle{Radius: 5},
        Rectangle{Width: 4, Height: 3},
        Circle{Radius: 2},
    }
    
    for _, s := range shapes {
        fmt.Printf("Area: %.2f\n", s.Area())
    }
}

הפרוסה shapes מכילה גם עיגולים וגם מלבנים. בעת איטרציה, כל איבר מגיב ל־Area() בהתאם לטיפוס שלו בפועל. זהו פולימורפיזם המיושם על אוספים: אותה לולאה מטפלת בכל סוגי הצורות באופן אחיד.

אוספים פולימורפיים חיוניים לבניית מערכות המעבדות פריטים מסוגים שונים: מערכת התראות ששולחת הודעות דוא״ל והודעות SMS, משחק שמעדכן סוגים שונים של אויבים, או מעבד מסמכים המטפל בפורמטים מרובים של קבצים. לאוסף לא אכפת מהסוגים הספציפיים: רק שכל רכיב יספק את ההתנהגות הנדרשת.

challenge icon

אתגר

קל

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

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

  • task.go: הגדירו ממשק Task שדורש מתודה Summary() string. הממשק הזה יהיה החוזה המשותף שכל סוגי המשימות צריכים לממש.
  • types.go: צרו שלושה סוגי משימות שונים, שכל אחד מהם מממש את הממשק Task:
    • BugFix עם השדות ID (מחרוזת) ו-Severity (מחרוזת). המתודה Summary() מחזירה Bug #[ID] ([Severity])
    • Feature עם השדות Name (מחרוזת) ו-Points (מספר שלם). המתודה Summary() מחזירה Feature: [Name] - [Points] pts
    • Documentation עם השדה Topic (מחרוזת). המתודה Summary() מחזירה Docs: [Topic]
  • main.go: צרו פונקציה בשם PrintBacklog שמקבלת פרוסה של Task ומדפיסה את הסיכום של כל משימה בשורה משלה. קראו את פרטי המשימות מהקלט, צרו משימה אחת מכל סוג, אספו את כולן לפרוסת []Task אחת והעבירו אותה אל PrintBacklog.

הקלט שיסופק יהיה בפורמט הבא:

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

לדוגמה, עבור 1042, critical, Dark Mode, 8 ו-API Reference, הפלט יהיה:

Bug #1042 (critical)
Feature: Dark Mode - 8 pts
Docs: API Reference

היתרון כאן הוא ש-PrintBacklog לא צריכה לוגיקה נפרדת עבור באגים, תכונות או תיעוד. היא פשוט עוברת על הפרוסה וקוראת ל-Summary() של כל איבר. כל סוג משימה מגיב בפורמט הייחודי שלו, וכך מודגם כיצד אוספים פולימורפיים מאפשרים לעבד סוגים מגוונים באופן אחיד.

נסו בעצמכם

package main

import (
	"fmt"
)

// TODO: צרו פונקציה בשם PrintBacklog שמקבלת פרוסה של Task
// ומדפיסה את הסיכום של כל משימה בשורה נפרדת

func main() {
	// קראו קלט
	var bugID string
	var bugSeverity string
	var featureName string
	var featurePoints int
	var docTopic string

	fmt.Scanln(&bugID)
	fmt.Scanln(&bugSeverity)
	fmt.Scanln(&featureName)
	fmt.Scanln(&featurePoints)
	fmt.Scanln(&docTopic)

	// TODO: צרו מופע אחד מכל סוג משימה (BugFix, Feature, Documentation)

	// TODO: אספו את כל המשימות לפרוסת []Task אחת

	// TODO: קראו ל־PrintBacklog עם פרוסת המשימות
}
quiz iconבחנו את עצמכם

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

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

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