Implementierung der Datenkapselung
Teil des Abschnitts Objektorientierte Programmierung der C#-Journey von Coddy. Lektion 33 von 70.
Datenkapselung geht über die bloße Verwendung von private Feldern hinaus. Es geht darum, Ihre Klasse so zu entwerfen, dass interne Implementierungsdetails für externen Code vollständig unsichtbar sind und nur das Notwendige über eine saubere öffentliche Schnittstelle offengelegt wird.
Betrachten Sie eine Klasse, die das Passwort eines Benutzers verwaltet. Sie möchten nicht, dass jemand auf das Passwort im Klartext zugreift – nicht einmal, um es zu lesen:
public class UserAccount
{
private string passwordHash;
public void SetPassword(string password)
{
passwordHash = HashPassword(password);
}
public bool VerifyPassword(string password)
{
return HashPassword(password) == passwordHash;
}
private string HashPassword(string password)
{
return password.GetHashCode().ToString();
}
}Beachten Sie, dass es keine Möglichkeit gibt, das Passwort oder gar den Hash abzurufen. Externer Code kann nur ein Passwort festlegen oder eines verifizieren – der interne Speichermechanismus ist vollständig verborgen. Die Methode HashPassword ist ebenfalls privat, da es sich um ein Implementierungsdetail handelt, das sich ändern könnte, ohne die Verwendung der Klasse zu beeinflussen.
Dieser Ansatz schützt Ihre Klasse vor Missbrauch und gibt Ihnen die Freiheit, Interna später zu ändern. Wenn Sie sich entscheiden, einen anderen Hashing-Algorithmus zu verwenden, bricht kein externer Code ab, da nichts davon abhing, wie das Passwort gespeichert wurde.
Aufgabe
EinfachLass uns ein sicheres Wallet-System entwickeln, das echtes Verbergen von Daten demonstriert. Du erstellst ein digitales Wallet, dessen Kontostand vollständig geschützt ist – externer Code kann nur einzahlen, abheben und prüfen, ob Transaktionen möglich sind, den tatsächlichen Kontostand aber niemals direkt sehen oder manipulieren.
Du organisierst deinen Code auf zwei Dateien:
Wallet.cs: Erstelle eineWallet-Klasse im NamespaceFinance, die ihren Kontostand vollständig verborgen hält. Das Wallet sollte Folgendes enthalten:- Ein privates Feld zum Speichern des Kontostands (Dezimalzahl)
- Eine private Methode
FormatBalance(), die den Kontostand als Währungszeichenfolge wie"$123.45"formatiert zurückgibt – dies ist eine interne Hilfsmethode, die nicht öffentlich zugänglich sein sollte - Eine öffentliche Methode
Deposit(decimal amount), die den Kontostand nur erhöht, wenn der Betrag positiv ist, und bei Erfolgtrue, andernfallsfalsezurückgibt - Eine öffentliche Methode
Withdraw(decimal amount), die den Kontostand nur verringert, wenn der Betrag positiv ist und den aktuellen Kontostand nicht überschreitet, und bei Erfolgtrue, andernfallsfalsezurückgibt - Eine öffentliche Methode
CanAfford(decimal amount), dietruezurückgibt, wenn der Kontostand größer oder gleich dem Betrag ist, andernfallsfalse - Eine öffentliche Methode
GetStatement(), die intern die private MethodeFormatBalance()verwendet und"Current balance: {formatted balance}"zurückgibt
Program.cs: Erstelle in deiner Hauptdatei einWalletund führe mithilfe von Eingabewerten eine Reihe von Transaktionen durch. Zeige, wie das Wallet seinen internen Zustand schützt und über seine öffentliche Schnittstelle dennoch nützliche Funktionen bereitstellt.
Du erhältst drei Eingaben:
- Ursprünglicher Einzahlungsbetrag (Dezimalzahl)
- Auszahlungsbetrag, der versucht werden soll (Dezimalzahl)
- Betrag, für den die Bezahlbarkeit geprüft werden soll (Dezimalzahl)
Gib die Ausgabe in diesem Format aus:
Deposit {amount}: {True/False}
{GetStatement() result}
Withdraw {amount}: {True/False}
{GetStatement() result}
Can afford {amount}: {True/False}Wenn die Eingaben beispielsweise 100.50, 30.25 und 80.00 lauten, sollte die Ausgabe wie folgt aussehen:
Deposit 100.50: True
Current balance: $100.50
Withdraw 30.25: True
Current balance: $70.25
Can afford 80.00: FalseDie wichtigste Erkenntnis ist, dass externer Code niemals direkt auf das Kontostandsfeld zugreift. Selbst die formatierte Kontostandszeichenfolge wird über eine öffentliche Methode bereitgestellt, die intern eine private Hilfsmethode verwendet. Das ist Datenverbergung – die Implementierungsdetails sind vollständig unsichtbar, und du kannst jederzeit ändern, wie der Kontostand gespeichert oder formatiert wird, ohne Code zu beschädigen, der dein Wallet verwendet!
Probier es selbst
using System;
using Finance;
class Program
{
public static void Main(string[] args)
{
// Eingabewerte lesen
decimal depositAmount = Convert.ToDecimal(Console.ReadLine());
decimal withdrawAmount = Convert.ToDecimal(Console.ReadLine());
decimal checkAmount = Convert.ToDecimal(Console.ReadLine());
// TODO: Eine Wallet-Instanz erstellen
// TODO: Einzahlung durchführen und Ergebnis im Format "Deposit {amount}: {True/False}" ausgeben
// TODO: Den Kontoauszug mit GetStatement() ausgeben
// TODO: Auszahlung durchführen und Ergebnis im Format "Withdraw {amount}: {True/False}" ausgeben
// TODO: Den Kontoauszug mit GetStatement() ausgeben
// TODO: Erschwinglichkeit prüfen und Ergebnis im Format "Can afford {amount}: {True/False}" ausgeben
}
}
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