Menu
Coddy logo textTech

Classi sealed

Fa parte della sezione Programmazione orientata agli oggetti del percorso C# di Coddy. Lezione 22 di 70.

A volte vuoi interrompere la catena di ereditarietà. La parola chiave sealed impedisce di ereditare una classe, bloccandone l’implementazione affinché nessun’altra classe possa estenderla.

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

// Questo causerebbe un errore di compilazione:
// public class SuperDog : FinalDog { }

Perché dovresti sigillare una classe? La sicurezza e l’integrità della progettazione sono motivi comuni. Quando hai progettato con cura una classe e non vuoi che qualcuno ne modifichi il comportamento tramite l’ereditarietà, sigillarla garantisce che la tua implementazione rimanga intatta.

Puoi anche sigillare singoli metodi invece di intere classi. In questo modo impedisci ulteriori override, consentendo comunque di ereditare la classe stessa:

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

public class Puppy : Dog
{
    // Non è possibile eseguire l'override di Speak() perché è sealed
    // Ma si possono aggiungere nuovi metodi
    public void Whimper()
    {
        Console.WriteLine("Whimper...");
    }
}

Nota che sealed su un metodo deve essere combinato con override. Puoi sigillare solo un metodo che era già virtuale in una classe genitore. Questo ti dà un controllo preciso: consentire alcune personalizzazioni nella gerarchia di ereditarietà, poi bloccarle in un punto specifico.

challenge icon

Sfida

Facile

Costruiamo un sistema di elaborazione dei pagamenti che mostra come usare sealed per bloccare implementazioni critiche. Creerai una gerarchia in cui alcuni metodi di pagamento possono essere estesi, mentre quelli più sicuri sono sealed per impedire qualsiasi modifica.

Creerai quattro file per organizzare il codice:

  • PaymentMethod.cs: definisci una classe PaymentMethod nello spazio dei nomi Payments. Questa classe base ha una proprietà Name (string) e un costruttore che la imposta. Includi un metodo virtual chiamato ProcessPayment(decimal amount) che restituisce "Processing ${amount} via {Name}".
  • CreditCardPayment.cs: definisci una classe CreditCardPayment nello spazio dei nomi Payments che eredita da PaymentMethod. Aggiungi una proprietà CardNumber (string). Il costruttore accetta il nome e il numero della carta e usa base per passare il nome. Esegui l'override di ProcessPayment con la parola chiave sealed, in modo che nessuna classe derivata possa modificare ulteriormente questo comportamento. Dovrebbe restituire "Charging ${amount} to card ending in {last 4 digits of CardNumber}".
  • BankTransfer.cs: definisci una classe sealed chiamata BankTransfer nello spazio dei nomi Payments che eredita da PaymentMethod. L'intera classe è sealed: nessuno può ereditarne. Aggiungi una proprietà BankName (string). Il costruttore accetta il nome e il nome della banca. Esegui l'override di ProcessPayment in modo che restituisca "Transferring ${amount} from {BankName}".
  • Program.cs: nel file principale, crea istanze di tutti e tre i tipi di pagamento usando i valori di input. Memorizzale come riferimenti PaymentMethod e chiama ProcessPayment su ciascuna per mostrare il polimorfismo con implementazioni sealed.

Riceverai tre input:

  • Numero della carta di credito (16 cifre)
  • Nome della banca
  • Importo del pagamento

Stampa il risultato dell'elaborazione di un pagamento con ciascun metodo:

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

Ad esempio, se gli input sono 1234567890123456, First National e 150.00, l'output dovrebbe essere:

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

Usa "Generic" come nome per l'istanza base PaymentMethod, "Credit Card" per il pagamento con carta di credito e "Bank Transfer" per il bonifico bancario.

Il metodo sealed in CreditCardPayment garantisce che, se qualcuno crea una sottoclasse, non possa modificare il modo in cui vengono elaborati i pagamenti con carta di credito. La classe sealed BankTransfer impedisce del tutto qualsiasi ereditarietà: entrambi sono importanti schemi di sicurezza nei sistemi di pagamento!

Provalo tu

using System;
using Payments;

class Program
{
    public static void Main(string[] args)
    {
        // Leggi gli input
        string cardNumber = Console.ReadLine();
        string bankName = Console.ReadLine();
        decimal amount = Convert.ToDecimal(Console.ReadLine());
        
        // TODO: Crea un'istanza della classe base PaymentMethod con nome "Generic"
        // Memorizzala come riferimento di tipo PaymentMethod
        
        // TODO: Crea un'istanza di CreditCardPayment con nome "Credit Card" e il numero della carta
        // Memorizzala come riferimento di tipo PaymentMethod
        
        // TODO: Crea un'istanza di BankTransfer con nome "Bank Transfer" e il nome della banca
        // Memorizzala come riferimento di tipo PaymentMethod
        
        // TODO: Chiama ProcessPayment su ciascuna istanza e stampa i risultati
        // Ogni risultato deve essere su una riga a sé
    }
}
quiz iconMettiti alla prova

Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.

Tutte le lezioni di Programmazione orientata agli oggetti

Esercitati da solo: Compilatore C# online