Menu
Coddy logo textTech

Incrustación de múltiples structs

Parte de la sección Programación Orientada a Objetos del Journey de GO de Coddy. Lección 37 de 107.

Go te permite incrustar varias estructuras dentro de una sola estructura, combinando comportamientos de diferentes fuentes. Esto es similar a la herencia múltiple en otros lenguajes, pero con el enfoque de composición de Go.

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
}

La estructura Service ahora tiene acceso a los métodos de ambos tipos integrados:

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

Al incorporar varias estructuras, puede producirse un conflicto de nombres si dos tipos incorporados tienen métodos con el mismo nombre. Go no resuelve automáticamente esta ambigüedad:

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() - error de compilación: selector ambiguo
    fmt.Println(c.A.Greet())  // Hola desde A
    fmt.Println(c.B.Greet())  // Hola desde B
}

Cuando surjan conflictos, debes especificar explícitamente qué método del tipo incrustado quieres llamar usando el nombre del tipo como calificador.

challenge icon

Desafío

Fácil

Construyamos un sistema de dispositivos domésticos inteligentes que combine varias capacidades mediante la inclusión de estructuras. Crearás un dispositivo que pueda controlar la iluminación y reproducir música mediante la inclusión de tipos de controlador independientes.

Organizarás tu código en tres archivos:

  • controllers.go: Crea dos estructuras de controlador independientes que proporcionen distintas capacidades:
    • Un LightController con un campo Brightness (int) y un método SetLight(level int) string que devuelva Light set to [level]%
    • Un AudioController con un campo Volume (int) y un método SetVolume(level int) string que devuelva Volume set to [level]%
    Ambos controladores también deben tener un método Status() string. Esto crea un conflicto de nombres que tendrás que resolver. LightController.Status() debe devolver Brightness: [Brightness]% y AudioController.Status() debe devolver Volume: [Volume]%.
  • device.go: Crea una estructura SmartDevice con un campo Name que incluya tanto LightController como AudioController. Añade un método llamado FullStatus() string que devuelva el nombre del dispositivo junto con los estados de ambos controladores, resolviendo la ambigüedad mediante una llamada explícita al método Status() de cada tipo incluido.
  • main.go: Lee la configuración del dispositivo desde la entrada, crea un SmartDevice, usa los métodos promovidos para establecer los niveles de iluminación y volumen, y después muestra el estado completo.

Se proporcionarán las siguientes entradas:

  • Línea 1: Nombre del dispositivo
  • Línea 2: Nivel de brillo inicial (entero)
  • Línea 3: Nivel de volumen inicial (entero)
  • Línea 4: Nuevo nivel de brillo que se establecerá (entero)
  • Línea 5: Nuevo nivel de volumen que se establecerá (entero)

Tu método FullStatus() debe devolver:

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

Imprime los resultados de llamar a SetLight y SetVolume (que se promueven desde los tipos incluidos) y después imprime el estado completo.

Por ejemplo, dadas las entradas Living Room Hub, 50, 30, 75 y 60, tu salida debería ser:

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

Observa cómo SetLight y SetVolume están directamente disponibles en SmartDevice mediante la promoción de métodos, pero Status() requiere una calificación explícita porque ambos tipos incluidos tienen ese método.

Pruébalo tú mismo

package main

import (
	"fmt"
)

func main() {
	// Leer entrada
	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: Crea un SmartDevice con el nombre dado y los valores iniciales

	// TODO: Usa el método promovido SetLight e imprime el resultado

	// TODO: Usa el método promovido SetVolume e imprime el resultado

	// TODO: Imprime el estado completo usando el método FullStatus()
}
quiz iconPonte a prueba

Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.

Todas las lecciones de Programación Orientada a Objetos

Practica por tu cuenta: Compilador de Go online