Menu
Coddy logo textTech

Shadowing de métodos incrustados

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

A veces necesitas que la estructura externa proporcione su propia implementación de un método que el tipo integrado ya tiene. Esto se denomina ocultación y te permite reemplazar métodos promovidos con un comportamiento personalizado.

Cuando defines un método en la estructura externa con el mismo nombre que un método incorporado, el método externo tiene prioridad:

type Animal struct {
    Name string
}

func (a Animal) Speak() string {
    return "Some sound"
}

type Dog struct {
    Animal
    Breed string
}

func (d Dog) Speak() string {
    return "Woof!"
}

Ahora, cuando llamas a Speak() en un Dog, se utiliza el método externo:

func main() {
    d := Dog{Animal: Animal{Name: "Rex"}, Breed: "Labrador"}
    
    fmt.Println(d.Speak())        // Woof! - método de Dog
    fmt.Println(d.Animal.Speak()) // Algún sonido - método de Animal
}

El método integrado no ha desaparecido. Aún puedes acceder a él explícitamente mediante el nombre del tipo integrado. Este patrón resulta útil cuando quieres personalizar el comportamiento y mantener disponible la implementación original, quizá para llamarla desde dentro de tu método sobrescrito:

func (d Dog) Speak() string {
    return d.Animal.Speak() + " (but actually Woof!)"
}

El sombreado te da control sobre qué comportamiento se expone, al tiempo que mantiene el acceso al original mediante una calificación explícita.

challenge icon

Desafío

Fácil

Construyamos un sistema de notificaciones en el que diferentes canales de notificación puedan personalizar la forma en que formatean y entregan los mensajes. Usarás el sombreado de métodos para permitir que canales específicos sobrescriban el comportamiento predeterminado y, al mismo tiempo, puedan acceder a la implementación original cuando sea necesario.

Organizarás tu código en tres archivos:

  • base.go: Crea una estructura BaseNotification con campos Title y Priority (ambos de tipo string). Asígnale un método Format() string que devuelva la notificación en un formato estándar: [Priority] Title.
  • channels.go: Crea dos tipos de canales de notificación que incorporen BaseNotification y oculten el método Format con sus propias implementaciones:
    • EmailNotification con un campo Recipient. Su método Format() debe devolver Email to [Recipient]: [Priority] Title
    • SlackNotification con un campo Channel. Su método Format() debe llamar al método BaseNotification.Format() incorporado y anteponer #[Channel]: al resultado
  • main.go: Lee los detalles de la notificación desde la entrada, crea ambos tipos de notificaciones y demuestra el sombreado imprimiendo:
    1. La salida formateada de EmailNotification (usando su método oculto)
    2. El formato base de EmailNotification (llamando explícitamente al método incorporado)
    3. La salida formateada de SlackNotification (que utiliza internamente el método base)

Se proporcionarán las siguientes entradas:

  • Línea 1: Título de la notificación
  • Línea 2: Nivel de prioridad
  • Línea 3: Destinatario del correo electrónico
  • Línea 4: Nombre del canal de Slack

Por ejemplo, dadas las entradas Server Alert, HIGH, admin@company.com y ops-alerts, la salida debería ser:

Email to admin@company.com: HIGH Server Alert
[HIGH] Server Alert
#ops-alerts: [HIGH] Server Alert

Observa cómo EmailNotification reemplaza por completo el formato base, mientras que SlackNotification lo mejora llamando al método original y añadiendo el contexto del canal. Ambos enfoques demuestran diferentes formas de utilizar eficazmente el sombreado de métodos.

Pruébalo tú mismo

package main

import (
	"bufio"
	"fmt"
	"os"
)

func main() {
	scanner := bufio.NewScanner(os.Stdin)
	
	// Lee el título de la notificación
	scanner.Scan()
	title := scanner.Text()
	
	// Lee el nivel de prioridad
	scanner.Scan()
	priority := scanner.Text()
	
	// Lee el destinatario del email
	scanner.Scan()
	recipient := scanner.Text()
	
	// Lee el nombre del canal de Slack
	scanner.Scan()
	channel := scanner.Text()
	
	// TODO: Crea un EmailNotification con la notificación base, title, priority y recipient
	
	// TODO: Crea un SlackNotification con la notificación base, title, priority y channel
	
	// TODO: Imprime la salida formateada de EmailNotification (usando su método sombreado)
	
	// TODO: Imprime el formato base de EmailNotification (llamando explícitamente al método embebido)
	
	// TODO: Imprime la salida formateada de SlackNotification
	
	fmt.Println() // Marcador de posición - eliminar al implementar
}
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