Menu
CoddyTech

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 unterschiedlicher Typen in derselben Sammlung. Ein Slice eines Schnittstellentyps kann jeden Wert enthalten, der diese Schnittstelle erfüllt, sodass du verwandte, aber unterschiedliche Typen gruppieren kannst.

Stell dir ein Szenario vor, in dem du verschiedene Formen verwalten musst. Statt für jeden Typ ein eigenes Slice zu verwenden, kannst du ein einzelnes 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())
    }
}

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

Polymorphe Sammlungen sind unverzichtbar, wenn du Systeme entwickelst, die unterschiedliche Elemente verarbeiten: ein Benachrichtigungssystem, das E-Mails und SMS-Nachrichten versendet, ein Spiel, das verschiedene Gegnertypen aktualisiert, oder ein Dokumentenprozessor, der mehrere Dateiformate verarbeitet. Der Sammlung sind die konkreten Typen egal: Entscheidend ist nur, dass jedes Element das erforderliche Verhalten bereitstellt.

challenge icon

Aufgabe

Einfach

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

Du organisierst deinen Code in drei Dateien:

  • task.go: Definiere eine Task-Schnittstelle, die eine Summary() string-Methode erfordert. 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). Summary() gibt Bug #[ID] ([Severity]) zurück.
    • Feature mit den Feldern Name (string) und Points (int). Summary() gibt Feature: [Name] - [Points] pts zurück.
    • Documentation mit dem Feld Topic (string). Summary() gibt Docs: [Topic] zurück.
  • main.go: Erstelle eine Funktion namens PrintBacklog, die einen Slice von Task entgegennimmt 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 ihn an PrintBacklog.

Die folgenden Eingaben werden bereitgestellt:

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

Wenn beispielsweise 1042, critical, Themes, 8 und API gegeben sind, sollte deine Ausgabe wie folgt aussehen:

Bug #1042 (critical)
Feature: Themes - 8 pts
Docs: API

Der Vorteil dabei ist, dass PrintBacklog keine separate Logik für Bugs, Features oder Dokumentation benötigt. Die Funktion durchläuft einfach den Slice und ruft für jedes Element Summary() auf. Jeder Aufgabentyp liefert sein eigenes, eindeutiges Format zurück. So zeigen polymorphe Sammlungen, wie sich unterschiedliche Typen einheitlich verarbeiten lassen.

Probier es selbst

package main

import (
	"fmt"
)

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

func main() {
	// Eingabe einlesen
	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 eine Aufgabe jedes Typs (BugFix, Feature, Documentation)

	// TODO: Fasse alle Aufgaben in einem einzigen []Task-Slice zusammen

	// TODO: Rufe PrintBacklog mit dem Slice der Aufgaben 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