Menu
Coddy logo textTech

Polymorphe Sammlungen

Teil des Abschnitts Objektorientierte Programmierung der GO-Journey von Coddy. Lektion 44 von 107.

Eine der leistungsfähigsten Anwendungen von Schnittstellen ist das Speichern verschiedener Typen in derselben Sammlung. Ein Slice eines Schnittstellentyps kann jeden Wert aufnehmen, der diese Schnittstelle erfüllt, sodass du verwandte, aber unterschiedliche Typen zusammen gruppieren kannst.

Stell dir ein Szenario vor, in dem du verschiedene Formen verwalten musst. Statt separate Slices für jeden Typ zu verwenden, kannst du eine einzige Slice des Interface-Typs verwenden:

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())
    }
}

Das Slice shapes enthält sowohl Kreise als auch Rechtecke. Beim Iterieren reagiert jedes Element entsprechend seinem tatsächlichen Typ auf Area(). Das ist Polymorphismus, angewendet auf Sammlungen: Dieselbe Schleife verarbeitet alle Formtypen einheitlich.

Polymorphe Sammlungen sind beim Erstellen von Systemen, die unterschiedliche Elemente verarbeiten, unverzichtbar: etwa ein Benachrichtigungssystem, das E-Mails und SMS-Nachrichten versendet, ein Spiel, das verschiedene Gegnertypen aktualisiert, oder ein Dokumentprozessor, der mehrere Dateiformate verarbeitet. Die Sammlung kümmert sich nicht um bestimmte Typen, sondern nur darum, dass jedes Element das erforderliche Verhalten bereitstellt.

challenge icon

Aufgabe

Einfach

Wir erstellen ein Aufgabenverwaltungssystem, das verschiedene Aufgabentypen über eine einheitliche Schnittstelle verarbeitet. Du erstellst verschiedene Aufgabentypen und verarbeitest sie gemeinsam in einer polymorphen Sammlung.

Du organisierst deinen Code auf drei Dateien verteilt:

  • task.go: Definiere eine Task-Schnittstelle, die eine Summary() string-Methode voraussetzt. Diese Schnittstelle bildet den gemeinsamen Vertrag, den alle Aufgabentypen erfüllen müssen.
  • types.go: Erstelle drei verschiedene Aufgabentypen, die jeweils die Task-Schnittstelle implementieren:
    • BugFix mit den Feldern ID (string) und Severity (string). Die Methode Summary() gibt Bug #[ID] ([Severity]) zurück.
    • Feature mit den Feldern Name (string) und Points (int). Die Methode Summary() gibt Feature: [Name] - [Points] pts zurück.
    • Documentation mit dem Feld Topic (string). Die Methode Summary() gibt Docs: [Topic] zurück.
  • main.go: Erstelle eine Funktion namens PrintBacklog, die ein Slice von Task akzeptiert und die Zusammenfassung jeder Aufgabe in einer eigenen Zeile ausgibt. Lies die Aufgabendetails aus der Eingabe, erstelle jeweils eine Aufgabe jedes Typs, sammle sie in einem einzigen []Task-Slice und übergib es an PrintBacklog.

Die folgenden Eingaben werden bereitgestellt:

  • Zeile 1: Bug-ID
  • Zeile 2: Schweregrad des Bugs
  • Zeile 3: Name des Features
  • Zeile 4: Feature-Punkte (Ganzzahl)
  • Zeile 5: Dokumentationsthema

Wenn beispielsweise 1042, critical, Dark Mode, 8 und API Reference gegeben sind, sollte deine Ausgabe folgendermaßen aussehen:

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

Die Stärke dieses Ansatzes liegt darin, dass PrintBacklog keine separate Logik für Bugs, Features oder Dokumentation benötigt. Die Funktion durchläuft einfach das Slice und ruft für jedes Element Summary() auf. Jeder Aufgabentyp reagiert mit seinem eigenen eindeutigen Format. So wird veranschaulicht, wie du mit polymorphen Sammlungen verschiedene Typen einheitlich verarbeiten kannst.

Probier es selbst

package main

import (
	"fmt"
)

// TODO: Erstelle eine PrintBacklog-Funktion, die ein Slice von Task akzeptiert
// und die Zusammenfassung jeder Task in einer eigenen Zeile ausgibt

func main() {
	// Eingabe lesen
	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: Erstelle je einen Task von jedem Typ (BugFix, Feature, Documentation)

	// TODO: Sammle alle Tasks in einem einzelnen []Task-Slice

	// TODO: Rufe PrintBacklog mit dem Slice der Tasks auf
}
quiz iconTeste dich selbst

Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.

Alle Lektionen in Objektorientierte Programmierung

Übe selbstständig: Online-Go-Compiler