Versiegelte Klassen
Teil des Abschnitts Objektorientierte Programmierung der C#-Journey von Coddy. Lektion 22 von 70.
Manchmal möchte man die Vererbungskette unterbrechen. Das Schlüsselwort sealed verhindert, dass eine Klasse geerbt wird, wodurch ihre Implementierung gesperrt wird, sodass keine andere Klasse sie erweitern kann.
public sealed class FinalDog : Animal
{
public override void Speak()
{
Console.WriteLine("Woof!");
}
}
// Dies würde zu einem Kompilierfehler führen:
// public class SuperDog : FinalDog { }Warum sollte man eine Klasse versiegeln? Sicherheit und Designintegrität sind häufige Gründe. Wenn Sie eine Klasse sorgfältig entworfen haben und nicht möchten, dass jemand ihr Verhalten durch Vererbung ändert, garantiert das Versiegeln, dass Ihre Implementierung intakt bleibt.
Sie können auch einzelne Methoden versiegeln, anstatt ganze Klassen. Dies verhindert weiteres Überschreiben, während die Klasse selbst weiterhin vererbt werden kann:
public class Dog : Animal
{
public sealed override void Speak()
{
Console.WriteLine("Woof!");
}
}
public class Puppy : Dog
{
// Speak() kann nicht überschrieben werden - es ist versiegelt (sealed)
// Aber es können neue Methoden hinzugefügt werden
public void Whimper()
{
Console.WriteLine("Whimper...");
}
}Beachte, dass sealed bei einer Methode mit override kombiniert werden muss. Du kannst nur eine Methode versiegeln, die in einer übergeordneten Klasse bereits virtuell war. Dadurch erhältst du präzise Kontrolle: Erlaube eine gewisse Anpassung in der Vererbungshierarchie und schränke sie dann an einem bestimmten Punkt ein.
Aufgabe
EinfachErstellen wir ein Zahlungsabwicklungssystem, das zeigt, wie man sealed verwendet, um kritische Implementierungen abzusichern. Du erstellst eine Hierarchie, in der bestimmte Zahlungsmethoden erweitert werden können, während die sichersten versiegelt sind, um Änderungen zu verhindern.
Du erstellst vier Dateien, um deinen Code zu organisieren:
PaymentMethod.cs: Definiere einePaymentMethod-Klasse im NamespacePayments. Diese Basisklasse verfügt über eineName-Eigenschaft (string) und einen Konstruktor, der sie festlegt. Füge einevirtual-Methode namensProcessPayment(decimal amount)hinzu, die"Processing ${amount} via {Name}"zurückgibt.CreditCardPayment.cs: Definiere eineCreditCardPayment-Klasse im NamespacePayments, die vonPaymentMethoderbt. Füge eineCardNumber-Eigenschaft (string) hinzu. Der Konstruktor akzeptiert den Namen und die Kartennummer und verwendetbase, um den Namen zu übergeben. ÜberschreibeProcessPaymentmit dem Schlüsselwortsealed, sodass keine weiteren abgeleiteten Klassen dieses Verhalten ändern können. Die Methode soll"Charging ${amount} to card ending in {last 4 digits of CardNumber}"zurückgeben.BankTransfer.cs: Definiere einesealed-Klasse namensBankTransferim NamespacePayments, die vonPaymentMethoderbt. Die gesamte Klasse ist versiegelt – niemand kann von ihr erben. Füge eineBankName-Eigenschaft (string) hinzu. Der Konstruktor akzeptiert den Namen und den Banknamen. ÜberschreibeProcessPayment, sodass"Transferring ${amount} from {BankName}"zurückgegeben wird.Program.cs: Erstelle in deiner Hauptdatei Instanzen aller drei Zahlungstypen mithilfe von Eingabewerten. Speichere sie alsPaymentMethod-Referenzen und rufe für jede InstanzProcessPaymentauf, um Polymorphismus mit versiegelten Implementierungen zu demonstrieren.
Du erhältst vier Eingaben:
- Kreditkartennummer (16 Ziffern)
- Bankname
- Zahlungsbetrag
Gib das Ergebnis der Zahlungsabwicklung über jede Methode aus:
{base PaymentMethod result}
{CreditCardPayment result}
{BankTransfer result}Wenn die Eingaben beispielsweise 1234567890123456, First National und 150.00 lauten, sollte die Ausgabe folgendermaßen aussehen:
Processing $150.00 via Generic
Charging $150.00 to card ending in 3456
Transferring $150.00 from First NationalVerwende "Generic" als Namen für die PaymentMethod-Instanz der Basisklasse, "Credit Card" für die Kreditkartenzahlung und "Bank Transfer" für die Banküberweisung.
Die versiegelte Methode in CreditCardPayment stellt sicher, dass jemand, der eine Unterklasse erstellt, nicht ändern kann, wie Kreditkartenzahlungen verarbeitet werden. Die versiegelte Klasse BankTransfer verhindert jegliche Vererbung – beide sind wichtige Sicherheitsmuster in Zahlungssystemen!
Probier es selbst
using System;
using Payments;
class Program
{
public static void Main(string[] args)
{
// Eingaben lesen
string cardNumber = Console.ReadLine();
string bankName = Console.ReadLine();
decimal amount = Convert.ToDecimal(Console.ReadLine());
// TODO: Erstelle eine Basis-PaymentMethod-Instanz mit dem Namen "Generic"
// Speichere sie als PaymentMethod-Referenz
// TODO: Erstelle eine CreditCardPayment-Instanz mit dem Namen "Credit Card" und der Kartennummer
// Speichere sie als PaymentMethod-Referenz
// TODO: Erstelle eine BankTransfer-Instanz mit dem Namen "Bank Transfer" und dem Banknamen
// Speichere sie als PaymentMethod-Referenz
// TODO: Rufe ProcessPayment für jedes Objekt auf und gib die Ergebnisse aus
// Jedes Ergebnis sollte in einer eigenen Zeile stehen
}
}
Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Objektorientierte Programmierung
1Grundlagen der OOP
Externe DateienNamespaces & DirektivenEinführung in Klassen & ObjekteDas 'this'-SchlüsselwortMethoden und ParameterFelder vs. EigenschaftenKonstruktorenObjektinitialisiererWiederholung – Einfacher Taschenrechner4Vererbung
Grundlegende Vererbungs-(:)-SyntaxDas „base“-Schlüsselwort„virtual“- und „override“-SchlüsselwörterVersiegelte KlassenDie „object“-BasisklasseWiederholung – Mitarbeiterhierarchie7Erweiterte Funktionen
Überladen von OperatorenIndexer (this[])ToString()-ÜberschreibungErweiterungsmethodenRückblick – Benutzerdefinierte Liste10Entwurfsmuster Teil 1
Einführung in EntwurfsmusterThread-sicheres SingletonFactory-MusterObserver-Muster (Events)Strategy-Muster13Abschließende Herausforderungen
E-Learning-PlattformKomponente für SpielfigurenFahrzeugvermietungsdienst2Eigenschaften & statische Member
Automatisch implementierte EigenschaftenNur lesbare/schreibbare EigenschaftenStatische Felder & MethodenStatische KlassenMember mit Ausdruckskörpern5Polymorphie & Interfaces
Compile- vs. Laufzeit-PolymorphieInterface vs. abstrakte KlasseMehrere InterfacesExplizite InterfacesUpcasting & DowncastingWiederholung – Formenrechner3Klassenarchitektur
Instanz- vs. statische DatenSchlüsselwörter 'readonly' & 'const'Backing FieldsRückblick – Bankkontenverwaltung6Kapselung
ZugriffsmodifikatorenEigenschaften zur KapselungImplementierung der DatenkapselungMuster für UnveränderlichkeitRückblick – SchülerdatenÜbe selbstständig: Online-C#-Compiler