Menu
Coddy logo textTech

Clases selladas (Sealed)

Parte de la sección Programación Orientada a Objetos del Journey de C# de Coddy — lección 22 de 70.

A veces querrás detener la cadena de herencia. La palabra clave sealed evita que una clase sea heredada, bloqueando su implementación para que ninguna otra clase pueda extenderla.

public sealed class FinalDog : Animal
{
    public override void Speak()
    {
        Console.WriteLine("Woof!");
    }
}

// Esto causaría un error de compilación:
// public class SuperDog : FinalDog { }

¿Por qué sellarías una clase? La seguridad y la integridad del diseño son razones comunes. Cuando has diseñado cuidadosamente una clase y no quieres que nadie cambie su comportamiento a través de la herencia, sellarla garantiza que tu implementación permanezca intacta.

También puedes sellar métodos individuales en lugar de clases enteras. Esto evita que se sigan sobrescribiendo, permitiendo al mismo tiempo que la propia clase sea heredada:

public class Dog : Animal
{
    public sealed override void Speak()
    {
        Console.WriteLine("Woof!");
    }
}

public class Puppy : Dog
{
    // No se puede sobrescribir Speak() - está sellado
    // Pero se pueden agregar nuevos métodos
    public void Whimper()
    {
        Console.WriteLine("Whimper...");
    }
}

Ten en cuenta que sealed en un método debe combinarse con override. Solo puedes sellar un método que ya era virtual en una clase base. Esto te brinda un control preciso: permite cierta personalización en la jerarquía de herencia y luego bloquéala en un punto específico.

challenge icon

Desafío

Fácil

Vamos a construir un sistema de procesamiento de pagos que demuestre cómo usar sealed para bloquear implementaciones críticas. Crearás una jerarquía donde ciertos métodos de pago pueden extenderse, pero los más seguros están sellados para evitar cualquier modificación.

Crearás cuatro archivos para organizar tu código:

  • PaymentMethod.cs: Define una clase PaymentMethod en el espacio de nombres Payments. Esta clase base tiene una propiedad Name (string) y un constructor que la establece. Incluye un método virtual llamado ProcessPayment(decimal amount) que devuelve "Processing ${amount} via {Name}".
  • CreditCardPayment.cs: Define una clase CreditCardPayment en el espacio de nombres Payments que hereda de PaymentMethod. Agrega una propiedad CardNumber (string). El constructor acepta el nombre y el número de tarjeta, usando base para pasar el nombre. Sobrescribe ProcessPayment con la palabra clave sealed para que ninguna clase derivada posterior pueda cambiar este comportamiento. Debe devolver "Charging ${amount} to card ending in {last 4 digits of CardNumber}".
  • BankTransfer.cs: Define una clase sealed llamada BankTransfer en el espacio de nombres Payments que hereda de PaymentMethod. Toda esta clase está sellada: nadie puede heredar de ella. Agrega una propiedad BankName (string). El constructor acepta el nombre y el nombre del banco. Sobrescribe ProcessPayment para devolver "Transferring ${amount} from {BankName}".
  • Program.cs: En tu archivo principal, crea instancias de los tres tipos de pago utilizando los valores de entrada. Almacénalas como referencias de PaymentMethod y llama a ProcessPayment en cada una para demostrar el polimorfismo con implementaciones selladas.

Recibirás cuatro entradas:

  • Número de tarjeta de crédito (16 dígitos)
  • Nombre del banco
  • Monto del pago

Imprime el resultado de procesar un pago a través de cada método:

{base PaymentMethod result}
{CreditCardPayment result}
{BankTransfer result}

Por ejemplo, si las entradas son 1234567890123456, First National, y 150.00, la salida debería ser:

Processing $150.00 via Generic
Charging $150.00 to card ending in 3456
Transferring $150.00 from First National

Usa "Generic" como nombre para la instancia base de PaymentMethod, "Credit Card" para el pago con tarjeta de crédito y "Bank Transfer" para la transferencia bancaria.

El método sellado en CreditCardPayment asegura que si alguien crea una subclase, no pueda cambiar cómo se procesan los pagos con tarjeta de crédito. La clase sellada BankTransfer evita cualquier herencia en absoluto; ¡ambos son patrones de seguridad importantes en los sistemas de pago!

Hoja de referencia

La palabra clave sealed evita que una clase sea heredada o que un método sea sobrescrito más adelante en la cadena de herencia.

Sellar una clase:

public sealed class FinalDog : Animal
{
    public override void Speak()
    {
        Console.WriteLine("Woof!");
    }
}

// This would cause a compile error:
// public class SuperDog : FinalDog { }

Las clases selladas se utilizan por seguridad e integridad del diseño, asegurando que la implementación no pueda ser modificada a través de la herencia.

Sellar un método:

public class Dog : Animal
{
    public sealed override void Speak()
    {
        Console.WriteLine("Woof!");
    }
}

public class Puppy : Dog
{
    // Cannot override Speak() - it's sealed
    // But can add new methods
    public void Whimper()
    {
        Console.WriteLine("Whimper...");
    }
}

La palabra clave sealed en un método debe combinarse con override. Solo se pueden sellar métodos que ya eran virtual en una clase base. Esto permite la personalización hasta un punto específico de la jerarquía y luego la bloquea.

Pruébalo tú mismo

using System;
using Payments;

class Program
{
    public static void Main(string[] args)
    {
        // Leer las entradas
        string cardNumber = Console.ReadLine();
        string bankName = Console.ReadLine();
        decimal amount = Convert.ToDecimal(Console.ReadLine());
        
        // TODO: Crear una instancia base de PaymentMethod con el nombre "Generic"
        // Almacenarla como una referencia de PaymentMethod
        
        // TODO: Crear una instancia de CreditCardPayment con el nombre "Credit Card" y el número de tarjeta
        // Almacenarla como una referencia de PaymentMethod
        
        // TODO: Crear una instancia de BankTransfer con el nombre "Bank Transfer" y el nombre del banco
        // Almacenarla como una referencia de PaymentMethod
        
        // TODO: Llamar a ProcessPayment en cada una e imprimir los resultados
        // Cada resultado debe estar en su propia línea
    }
}
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