Menu
CoddyTech

Mehrere Structs einbetten

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

In Go kannst du mehrere Structs in ein einzelnes Struct einbetten und so Verhaltensweisen aus verschiedenen Quellen kombinieren. Das ähnelt der Mehrfachvererbung in anderen Sprachen, folgt aber Gos Ansatz der Komposition.

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
}

Die Service-Struktur hat jetzt Zugriff auf Methoden beider eingebetteter Typen:

func main() {
    s := Service{Name: "OrderService"}
    fmt.Println(s.Log("started"))      // LOG: gestartet
    fmt.Println(s.Notify("new order")) // NOTIFY: neue Bestellung
}

Beim Einbetten mehrerer Strukturen kann ein Namenskonflikt auftreten, wenn zwei eingebettete Typen Methoden mit demselben Namen haben. Go löst diese Mehrdeutigkeit nicht automatisch auf:

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() - Kompilierungsfehler: mehrdeutiger Selektor
    fmt.Println(c.A.Greet())  // Hallo von A
    fmt.Println(c.B.Greet())  // Hallo von B
}

Wenn Konflikte auftreten, musst du ausdrücklich angeben, die Methode welchen eingebetteten Typs du aufrufen möchtest, indem du den Typnamen als Qualifizierer verwendest.

challenge icon

Aufgabe

Einfach

Lass uns ein Smart-Home-Gerätesystem erstellen, das mithilfe der Einbettung von Structs mehrere Funktionen vereint. Du erstellst ein Gerät, das sowohl die Beleuchtung steuern als auch Musik abspielen kann, indem du separate Controller-Typen einbettest.

Du organisierst deinen Code in drei Dateien:

  • controllers.go: Erstelle zwei unabhängige Controller-Structs, die unterschiedliche Funktionen bereitstellen:
    • Einen LightController mit einem Feld Brightness (int) und einer Methode SetLight(level int) string, die Light set to [level]% zurückgibt
    • Einen AudioController mit einem Feld Volume (int) und einer Methode SetVolume(level int) string, die Volume set to [level]% zurückgibt
    Beide Controller sollten außerdem eine Methode Status() string haben. Dadurch entsteht ein Namenskonflikt, den du behandeln musst. LightController.Status() sollte Brightness: [Brightness]% zurückgeben und AudioController.Status() sollte Volume: [Volume]% zurückgeben.
  • device.go: Erstelle ein Struct SmartDevice mit einem Feld Name, das sowohl LightController als auch AudioController einbettet. Füge eine Methode namens FullStatus() string hinzu, die den Gerätenamen zusammen mit den Statusangaben beider Controller zurückgibt. Löse dabei die Mehrdeutigkeit, indem du die Methode Status() jedes eingebetteten Typs ausdrücklich aufrufst.
  • main.go: Lies die Gerätekonfiguration aus der Eingabe, erstelle ein SmartDevice, verwende die übernommenen Methoden, um die Licht- und Lautstärkestufen festzulegen, und gib dann den vollständigen Status aus.

Es werden die folgenden Eingaben bereitgestellt:

  • Zeile 1: Gerätename
  • Zeile 2: Anfangshelligkeit (Ganzzahl)
  • Zeile 3: Anfangslautstärke (Ganzzahl)
  • Zeile 4: Neue einzustellende Helligkeit (Ganzzahl)
  • Zeile 5: Neue einzustellende Lautstärke (Ganzzahl)

Deine Methode FullStatus() sollte Folgendes zurückgeben:

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

Gib die Ergebnisse der Aufrufe von SetLight und SetVolume aus (diese werden von den eingebetteten Typen übernommen) und gib anschließend den vollständigen Status aus.

Wenn zum Beispiel Lounge, 50, 30, 75 und 60 angegeben werden, sollte deine Ausgabe so aussehen:

Light set to 75%
Volume set to 60%
Lounge - Brightness: 75%, Volume: 60%

Beachte, dass SetLight und SetVolume dank Methodenübernahme direkt über SmartDevice zugänglich sind, während für Status() eine ausdrückliche Qualifizierung erforderlich ist, weil beide eingebetteten Typen diese Methode haben.

Probier es selbst

package main

import (
	"fmt"
)

func main() {
	// Eingaben einlesen
	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: Ein SmartDevice mit dem angegebenen Namen und den Anfangswerten erstellen

	// TODO: Die übernommene Methode SetLight verwenden und das Ergebnis ausgeben

	// TODO: Die übernommene Methode SetVolume verwenden und das Ergebnis ausgeben

	// TODO: Den vollständigen Status mit der Methode FullStatus() ausgeben
}
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