Menu
Coddy logo textTech

Composición sobre herencia

Parte de la sección Programación Orientada a Objetos del Journey de C# de Coddy. Lección 41 de 70.

La herencia crea un acoplamiento estrecho entre las clases. Cuando Car hereda de Vehicle, cualquier cambio en Vehicle puede romper Car. La composición ofrece una alternativa más flexible: en lugar de heredar el comportamiento, una clase contiene objetos que proporcionan ese comportamiento.

Considera un personaje de juego que puede moverse y atacar. Con la herencia, podrías crear una jerarquía compleja. Con la composición, simplemente proporcionas al personaje los componentes que necesita:

public class MovementBehavior
{
    public void Move() => Console.WriteLine("Moving...");
}

public class AttackBehavior
{
    public void Attack() => Console.WriteLine("Attacking!");
}

public class Character
{
    private MovementBehavior movement = new MovementBehavior();
    private AttackBehavior attack = new AttackBehavior();
    
    public void Move() => movement.Move();
    public void Attack() => attack.Attack();
}

La diferencia clave es la relación. La herencia representa «es-un» (un Dog es un Animal), mientras que la composición representa «tiene-un» (un Character tiene un comportamiento de movimiento). La composición te permite intercambiar comportamientos en tiempo de ejecución, combinar capacidades libremente y evitar el frágil problema de la clase base.

Usa la herencia cuando exista una relación jerárquica genuina. Elige la composición cuando necesites flexibilidad, cuando los comportamientos puedan compartirse entre clases no relacionadas o cuando quieras cambiar el comportamiento dinámicamente.

challenge icon

Desafío

Fácil

Construyamos un sistema de notificaciones que demuestre el poder de la composición frente a la herencia. En lugar de crear una jerarquía compleja de clases de notificación, compondrás un NotificationSender proporcionándole componentes de comportamiento intercambiables.

Organizarás tu código en tres archivos:

  • Behaviors.cs: crea dos clases de comportamiento en el espacio de nombres Notifications que gestionen distintos aspectos del envío de notificaciones:
    • FormattingBehavior: tiene un método Format(string message) que devuelve el mensaje envuelto con [ALERT] al principio y [END] al final
    • DeliveryBehavior: tiene un método Deliver(string channel, string message) que devuelve una cadena con el formato Sending via {channel}: {message}
  • NotificationSender.cs: crea una clase NotificationSender en el espacio de nombres Notifications que use la composición para combinar comportamientos. Tu emisor debe:
    • Contener instancias de FormattingBehavior y DeliveryBehavior como campos privados
    • Tener una propiedad Channel (string) que almacene el nombre del canal de entrega
    • Tener un constructor que acepte el nombre del canal
    • Tener un método Send(string message) que primero dé formato al mensaje usando el comportamiento de formato, después lo entregue usando el comportamiento de entrega y devuelva el resultado final
  • Program.cs: en tu archivo principal, crea un NotificationSender con un canal obtenido de la entrada y después envía un mensaje obtenido de la entrada. Imprime el resultado para mostrar cómo funcionan conjuntamente los comportamientos compuestos.

Recibirás dos entradas:

  • El nombre del canal de entrega (por ejemplo, Email, SMS)
  • El mensaje que se enviará

Imprime el resultado de llamar a Send() en tu emisor de notificaciones.

Por ejemplo, si las entradas son Email y Server is down, la salida debería ser:

Sending via Email: [ALERT] Server is down [END]

Observa que NotificationSender no hereda de nada: simplemente «tiene» comportamientos de formato y entrega. Este enfoque de composición significa que podrías intercambiar fácilmente cualquiera de los dos comportamientos sin cambiar la clase emisora, ¡o reutilizar estos comportamientos en clases completamente diferentes!

Pruébalo tú mismo

using System;
using Notifications;

class Program
{
    public static void Main(string[] args)
    {
        // Lee la entrada
        string channel = Console.ReadLine();
        string message = Console.ReadLine();

        // TODO: Crea un NotificationSender con el canal
        
        // TODO: Envía el mensaje e imprime el resultado
        
    }
}
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 C# online