Classes scellées
Fait partie de la section Programmation Orientée Objet du Journey C# de Coddy — leçon 22 sur 70.
Parfois, vous souhaitez arrêter la chaîne d'héritage. Le mot-clé sealed empêche une classe d'être héritée, verrouillant son implémentation afin qu'aucune autre classe ne puisse l'étendre.
public sealed class FinalDog : Animal
{
public override void Speak()
{
Console.WriteLine("Woof!");
}
}
// Cela provoquerait une erreur de compilation :
// public class SuperDog : FinalDog { }Pourquoi scelleriez-vous une classe ? La sécurité et l'intégrité de la conception sont des raisons courantes. Lorsque vous avez soigneusement conçu une classe et que vous ne voulez pas que quiconque modifie son comportement par héritage, le fait de la sceller garantit que votre implémentation reste intacte.
Vous pouvez également sceller des méthodes individuelles plutôt que des classes entières. Cela empêche toute redéfinition ultérieure tout en permettant à la classe elle-même d'être héritée :
public class Dog : Animal
{
public sealed override void Speak()
{
Console.WriteLine("Woof!");
}
}
public class Puppy : Dog
{
// Impossible de surcharger Speak() - elle est scellée (sealed)
// Mais on peut ajouter de nouvelles méthodes
public void Whimper()
{
Console.WriteLine("Whimper...");
}
}Notez que sealed sur une méthode doit être combiné avec override. Vous ne pouvez sceller une méthode que si elle était déjà virtuelle dans une classe parente. Cela vous donne un contrôle précis : autorisez une certaine personnalisation dans la hiérarchie d'héritage, puis verrouillez-la à un point précis.
Défi
FacileConstruisons un système de traitement des paiements qui démontre comment utiliser sealed pour verrouiller les implémentations critiques. Vous allez créer une hiérarchie où certaines méthodes de paiement peuvent être étendues, mais les plus sécurisées sont scellées pour empêcher toute modification.
Vous allez créer quatre fichiers pour organiser votre code :
PaymentMethod.cs: Définissez une classePaymentMethoddans l'espace de nomsPayments. Cette classe de base possède une propriétéName(string) et un constructeur qui la définit. Incluez une méthodevirtualappeléeProcessPayment(decimal amount)qui retourne"Processing ${amount} via {Name}".CreditCardPayment.cs: Définissez une classeCreditCardPaymentdans l'espace de nomsPaymentsqui hérite dePaymentMethod. Ajoutez une propriétéCardNumber(string). Le constructeur accepte le nom et le numéro de carte, en utilisantbasepour transmettre le nom. SurchargezProcessPaymentavec le mot-clésealedafin qu'aucune classe dérivée ultérieure ne puisse modifier ce comportement. Elle doit retourner"Charging ${amount} to card ending in {last 4 digits of CardNumber}".BankTransfer.cs: Définissez une classesealedappeléeBankTransferdans l'espace de nomsPaymentsqui hérite dePaymentMethod. Cette classe entière est scellée - personne ne peut en hériter. Ajoutez une propriétéBankName(string). Le constructeur accepte le nom et le nom de la banque. SurchargezProcessPaymentpour retourner"Transferring ${amount} from {BankName}".Program.cs: Dans votre fichier principal, créez des instances des trois types de paiement en utilisant les valeurs d'entrée. Stockez-les en tant que référencesPaymentMethodet appelezProcessPaymentsur chacune pour démontrer le polymorphisme avec des implémentations scellées.
Vous recevrez quatre entrées :
- Numéro de carte de crédit (16 chiffres)
- Nom de la banque
- Montant du paiement
Affichez le résultat du traitement d'un paiement par chaque méthode :
{base PaymentMethod result}
{CreditCardPayment result}
{BankTransfer result}Par exemple, si les entrées sont 1234567890123456, First National, et 150.00, la sortie devrait être :
Processing $150.00 via Generic
Charging $150.00 to card ending in 3456
Transferring $150.00 from First NationalUtilisez "Generic" comme nom pour l'instance de base PaymentMethod, "Credit Card" pour le paiement par carte de crédit, et "Bank Transfer" pour le virement bancaire.
La méthode scellée dans CreditCardPayment garantit que si quelqu'un crée une sous-classe, il ne peut pas modifier la façon dont les paiements par carte de crédit sont traités. La classe scellée BankTransfer empêche tout héritage - les deux sont des modèles de sécurité importants dans les systèmes de paiement !
Aide-mémoire
Le mot-clé sealed empêche une classe d'être héritée ou une méthode d'être redéfinie plus loin dans la chaîne d'héritage.
Sceller une classe :
public sealed class FinalDog : Animal
{
public override void Speak()
{
Console.WriteLine("Woof!");
}
}
// This would cause a compile error:
// public class SuperDog : FinalDog { }Les classes scellées sont utilisées pour la sécurité et l'intégrité de la conception, garantissant que l'implémentation ne peut pas être modifiée par héritage.
Sceller une méthode :
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...");
}
}Le mot-clé sealed sur une méthode doit être combiné avec override. Vous ne pouvez sceller que des méthodes qui étaient déjà virtual dans une classe parente. Cela permet une personnalisation jusqu'à un point spécifique de la hiérarchie, puis la verrouille.
Essayez vous-même
using System;
using Payments;
class Program
{
public static void Main(string[] args)
{
// Lire les entrées
string cardNumber = Console.ReadLine();
string bankName = Console.ReadLine();
decimal amount = Convert.ToDecimal(Console.ReadLine());
// TODO: Créer une instance de base PaymentMethod avec le nom "Generic"
// La stocker en tant que référence PaymentMethod
// TODO: Créer une instance CreditCardPayment avec le nom "Credit Card" et le numéro de carte
// La stocker en tant que référence PaymentMethod
// TODO: Créer une instance BankTransfer avec le nom "Bank Transfer" et le nom de la banque
// La stocker en tant que référence PaymentMethod
// TODO: Appeler ProcessPayment sur chacune et afficher les résultats
// Chaque résultat doit être sur sa propre ligne
}
}
Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.
Toutes les leçons de Programmation Orientée Objet
1Fondamentaux de la POO
Fichiers externesEspaces de noms et directivesIntro aux classes et objetsLe mot-clé 'this'Méthodes et paramètresChamps vs PropriétésConstructeursInitialiseurs d'objetsRécapitulatif - Calculatrice simple4Héritage
Syntaxe de base de l'héritage (:)Le mot-clé 'base'Mots-clés Virtual & OverrideClasses scelléesLa classe de base 'object'Récapitulatif - Hiérarchie des employés7Fonctionnalités avancées
Surcharge d'opérateursIndexeurs (this[])Redéfinition de ToString()Méthodes d'extensionRécapitulatif - Liste personnalisée10Patrons de conception - Partie 1
Introduction aux patrons de conceptionSingleton Thread-SafePatron FabriquePatron Observateur (Événements)Patron Stratégie2Propriétés et membres statiques
Propriétés auto-implémentéesPropriétés en lecture/écriture seuleChamps et méthodes statiquesClasses statiquesMembres à corps d'expression5Polymorphisme & Interfaces
Polymorphisme : Compilation vs ExécutionInterface vs Classe AbstraiteInterfaces MultiplesInterfaces ExplicitesUpcasting & DowncastingRécapitulatif - Calculateur de Formes8Concepts avancés de la POO
Composition plutôt qu'héritageGénériques (Classes et Méthodes)Délégués et ÉvénementsAttributs et RéflexionIDisposable et l'instruction usingBases de l'Injection de Dépendances11Patrons de conception, Partie 2
Patron CommandePatron AdaptateurPatron DécorateurPatron Méthode TemplatePatron ÉtatPatron Composite3Architecture des classes
Données d'instance vs statiquesMots-clés 'readonly' & 'const'Champs de supportRécapitulatif - Gestionnaire de compte bancaire6Encapsulation
Modificateurs d'accèsPropriétés pour l'encapsulationImplémentation du masquage de donnéesPatterns d'immuabilitéRécapitulatif - Dossiers d'étudiants12Projet : Système de gestion de bibliothèque
Structure du projetModèles Livre et Utilisateur