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.
Sfida
FacileCostruiamo 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 classePaymentMethodnello spazio dei nomiPayments. Questa classe base ha una proprietàName(string) e un costruttore che la imposta. Includi un metodovirtualchiamatoProcessPayment(decimal amount)che restituisce"Processing ${amount} via {Name}".CreditCardPayment.cs: definisci una classeCreditCardPaymentnello spazio dei nomiPaymentsche eredita daPaymentMethod. Aggiungi una proprietàCardNumber(string). Il costruttore accetta il nome e il numero della carta e usabaseper passare il nome. Esegui l'override diProcessPaymentcon la parola chiavesealed, 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 classesealedchiamataBankTransfernello spazio dei nomiPaymentsche eredita daPaymentMethod. 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 diProcessPaymentin 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 riferimentiPaymentMethode chiamaProcessPaymentsu 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 NationalUsa "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é
}
}
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
1Fondamenti della programmazione orientata agli oggetti
File esterniNamespace e direttiveIntroduzione a classi e oggettiLa parola chiave "this"Metodi e parametriCampi e proprietàCostruttoriInizializzatori di oggettiRiepilogo - Calcolatrice semplice4Ereditarietà
Sintassi di base dell'ereditarietà (:)La parola chiave 'base'Parole chiave virtual e overrideClassi sealedLa classe base 'object'Riepilogo - Gerarchia dei dipendenti7Funzionalità avanzate
Sovraccarico degli operatoriIndicizzatori (this[])Override di ToString()Metodi di estensioneRiepilogo - Lista personalizzata10Pattern di progettazione Parte 1
Introduzione ai pattern di progettazioneSingleton thread-safePattern FactoryPattern Observer (eventi)Pattern Strategy2Proprietà e membri statici
Proprietà implementate automaticamenteProprietà di sola lettura e di sola scritturaCampi e metodi staticiClassi staticheMembri con corpo di espressione5Polimorfismo e interfacce
Polimorfismo a compile time e runtimeInterfaccia o classe astrattaInterfacce multipleInterfacce espliciteUpcasting e downcastingRipasso: calcolatore di forme8Concetti avanzati di programmazione a oggetti
Composizione invece dell'ereditarietàTipi generici (classi e metodi)Delegati ed eventiAttributi e reflectionIDisposable e istruzione usingNozioni di base sull'iniezione delle dipendenze11Pattern di progettazione, parte 2
Pattern del ComandoPattern dell’AdattatorePattern del DecoratorePattern Template MethodPattern dello StatoPattern Composito3Architettura delle classi
Dati di istanza vs staticiParole chiave 'readonly' e 'const'Campi di supportoRiepilogo - Gestore di conti bancari6Incapsulamento
Modificatori di accessoProprietà per l'incapsulamentoImplementazione dell'occultamento dei datiModelli di immutabilitàRiepilogo - Registri degli studentiEsercitati da solo: Compilatore C# online