Menu
Coddy logo textTech

Kolekcje polimorficzne

Część sekcji Programowanie obiektowe ścieżki GO w Coddy. Lekcja 44 z 107.

Jednym z najpotężniejszych zastosowań interfejsów jest przechowywanie różnych typów w tej samej kolekcji. Fragment typu interfejsowego może przechowywać dowolną wartość spełniającą wymagania tego interfejsu, dzięki czemu możesz grupować powiązane, ale różne typy.

Rozważ sytuację, w której musisz zarządzać różnymi kształtami. Zamiast osobnych wycinków dla każdego typu możesz użyć pojedynczego wycinka typu interfejsowego:

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

Wycinek shapes zawiera zarówno okręgi, jak i prostokąty. Podczas iterowania każdy element reaguje na Area() zgodnie ze swoim rzeczywistym typem. To polimorfizm zastosowany do kolekcji: ta sama pętla obsługuje jednolicie wszystkie typy kształtów.

Kolekcje polimorficzne są niezbędne podczas tworzenia systemów przetwarzających różnorodne elementy: systemu powiadomień wysyłającego e-maile i SMS-y, gry aktualizującej różne typy przeciwników lub procesora dokumentów obsługującego wiele formatów plików. Kolekcja nie przejmuje się konkretnymi typami — ważne jest tylko, aby każdy element zapewniał wymagane zachowanie.

challenge icon

Wyzwanie

Łatwy

Zbudujmy system zarządzania zadaniami, który obsługuje różne typy zadań za pośrednictwem ujednoliconego interfejsu. Utworzysz różne typy zadań i przetworzysz je wszystkie razem w polimorficznej kolekcji.

Rozmieścisz swój kod w trzech plikach:

  • task.go: Zdefiniuj interfejs Task, który wymaga metody Summary() string. Ten interfejs będzie wspólnym kontraktem, który muszą spełniać wszystkie typy zadań.
  • types.go: Utwórz trzy różne typy zadań, z których każdy implementuje interfejs Task:
    • BugFix z polami ID (string) i Severity (string). Metoda Summary() zwraca Bug #[ID] ([Severity])
    • Feature z polami Name (string) i Points (int). Metoda Summary() zwraca Feature: [Name] - [Points] pts
    • Documentation z polem Topic (string). Metoda Summary() zwraca Docs: [Topic]
  • main.go: Utwórz funkcję o nazwie PrintBacklog, która przyjmuje wycinek Task i wypisuje podsumowanie każdego zadania w osobnym wierszu. Odczytaj szczegóły zadań z danych wejściowych, utwórz po jednym zadaniu każdego typu, zbierz je wszystkie w jednym wycinku []Task i przekaż go do PrintBacklog.

Zostaną podane następujące dane wejściowe:

  • Wiersz 1: ID błędu
  • Wiersz 2: Ważność błędu
  • Wiersz 3: Nazwa funkcji
  • Wiersz 4: Liczba punktów funkcji (liczba całkowita)
  • Wiersz 5: Temat dokumentacji

Na przykład dla wartości 1042, critical, Dark Mode, 8 i API Reference wynik powinien wyglądać tak:

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

Zaletą tego rozwiązania jest to, że PrintBacklog nie potrzebuje osobnej logiki dla błędów, funkcji ani dokumentacji. Po prostu iteruje po wycinku i wywołuje Summary() dla każdego elementu. Każdy typ zadania zwraca własny, unikatowy format, pokazując, jak polimorficzne kolekcje pozwalają jednolicie przetwarzać różnorodne typy.

Spróbuj swoich sił

package main

import (
	"fmt"
)

// TODO: Utwórz funkcję PrintBacklog, która przyjmuje wycinek elementów Task
// i wypisuje podsumowanie każdego zadania w osobnym wierszu

func main() {
	// Wczytaj dane wejściowe
	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: Utwórz po jednym zadaniu każdego typu (BugFix, Feature, Documentation)

	// TODO: Zbierz wszystkie zadania w jednym wycinku []Task

	// TODO: Wywołaj PrintBacklog z wycinkiem zadań
}
quiz iconSprawdź się

Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.

Wszystkie lekcje w sekcji Programowanie obiektowe

Poćwicz samodzielnie: Kompilator Go online