Menu
Coddy logo textTech

Osadzanie wielu struktur

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

Go pozwala osadzać wiele struktur w jednej strukturze, łącząc zachowania z różnych źródeł. Jest to podobne do wielodziedziczenia w innych językach, ale wykorzystuje podejście Go oparte na kompozycji.

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
}

Struktura Service ma teraz dostęp do metod obu osadzonych typów:

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

Podczas osadzania wielu struktur może wystąpić konflikt nazw, jeśli dwa osadzone typy mają metody o tej samej nazwie. Go nie rozstrzyga automatycznie tej niejednoznaczności:

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() - błąd kompilacji: niejednoznaczny selektor
    fmt.Println(c.A.Greet())  // Witaj od A
    fmt.Println(c.B.Greet())  // Witaj od B
}

Gdy pojawiają się konflikty, musisz wyraźnie wskazać, metodę którego typu osadzonego chcesz wywołać, używając nazwy typu jako kwalifikatora.

challenge icon

Wyzwanie

Łatwy

Zbudujmy system urządzeń inteligentnego domu, który łączy wiele funkcji dzięki osadzaniu struktur. Utworzysz urządzenie, które może zarówno sterować oświetleniem, jak i odtwarzać muzykę, osadzając w nim osobne typy kontrolerów.

Podzielisz swój kod na trzy pliki:

  • controllers.go: Utwórz dwie niezależne struktury kontrolerów, które zapewniają różne funkcje:
    • LightController z polem Brightness (int) i metodą SetLight(level int) string, która zwraca Light set to [level]%
    • AudioController z polem Volume (int) i metodą SetVolume(level int) string, która zwraca Volume set to [level]%
    Oba kontrolery powinny mieć również metodę Status() string. Powoduje to konflikt nazw, z którym trzeba będzie sobie poradzić. LightController.Status() powinno zwracać Brightness: [Brightness]%, a AudioController.Status() powinno zwracać Volume: [Volume]%.
  • device.go: Utwórz strukturę SmartDevice z polem Name, która osadza zarówno LightController, jak i AudioController. Dodaj metodę o nazwie FullStatus() string, która zwraca nazwę urządzenia wraz ze statusem obu kontrolerów, rozwiązując niejednoznaczność przez jawne wywołanie metody Status() każdego osadzonego typu.
  • main.go: Odczytaj konfigurację urządzenia z wejścia, utwórz SmartDevice, użyj promowanych metod, aby ustawić poziomy oświetlenia i głośności, a następnie wyświetl pełny status.

Podane zostaną następujące dane wejściowe:

  • Wiersz 1: Nazwa urządzenia
  • Wiersz 2: Początkowy poziom jasności (liczba całkowita)
  • Wiersz 3: Początkowy poziom głośności (liczba całkowita)
  • Wiersz 4: Nowy poziom jasności do ustawienia (liczba całkowita)
  • Wiersz 5: Nowy poziom głośności do ustawienia (liczba całkowita)

Metoda FullStatus() powinna zwracać:

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

Wyświetl wyniki wywołania SetLight i SetVolume (które są promowane z osadzonych typów), a następnie wyświetl pełny status.

Na przykład dla danych Living Room Hub, 50, 30, 75 i 60 wynik powinien wyglądać następująco:

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

Zwróć uwagę, że metody SetLight i SetVolume są bezpośrednio dostępne w SmartDevice dzięki promocji metod, ale Status() wymaga jawnego określenia typu, ponieważ oba osadzone typy mają tę metodę.

Spróbuj swoich sił

package main

import (
	"fmt"
)

func main() {
	// Wczytaj dane wejściowe
	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: Utwórz SmartDevice o podanej nazwie i wartościach początkowych

	// TODO: Użyj promowanej metody SetLight i wypisz wynik

	// TODO: Użyj promowanej metody SetVolume i wypisz wynik

	// TODO: Wypisz pełny stan za pomocą metody FullStatus()
}
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