Implementazione dell'occultamento dei dati
Fa parte della sezione Programmazione orientata agli oggetti del percorso C# di Coddy. Lezione 33 di 70.
La protezione dei dati va oltre il semplice uso di campi private. Si tratta di progettare la tua classe in modo che i dettagli interni dell’implementazione siano completamente invisibili al codice esterno, esponendo solo ciò che è necessario tramite un’interfaccia pubblica chiara.
Considera una classe che tiene traccia della password di un utente. Non vuoi che nessuno possa accedere alla password in chiaro, nemmeno per leggerla:
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();
}
}Nota che non c’è modo di recuperare la password o persino l’hash. Il codice esterno può solo impostare una password o verificarne una: il meccanismo di archiviazione interno è completamente nascosto. Anche il metodo HashPassword è privato perché è un dettaglio di implementazione che potrebbe cambiare senza influire sul modo in cui viene usata la classe.
Questo approccio protegge la tua classe dall'uso improprio e ti dà la libertà di modificare gli elementi interni in seguito. Se decidi di usare un algoritmo di hashing diverso, nessun codice esterno si interrompe, perché nulla dipendeva dal modo in cui era archiviata la password.
Sfida
FacileCostruiamo un sistema di portafoglio sicuro che dimostri il vero occultamento dei dati. Creerai un portafoglio digitale in cui il saldo è completamente protetto dall'accesso diretto: il codice esterno può solo depositare, prelevare e verificare se le transazioni sono possibili, ma non può mai vedere o manipolare direttamente il saldo effettivo.
Organizzerai il codice in due file:
Wallet.cs: crea una classeWalletnello spazio dei nomiFinanceche mantiene il saldo completamente nascosto. Il portafoglio deve avere:- Un campo privato per memorizzare il saldo (decimal)
- Un metodo privato
FormatBalance()che restituisce il saldo formattato come stringa di valuta, ad esempio"$123.45"- è un helper interno che non dovrebbe essere esposto - Un metodo pubblico
Deposit(decimal amount)che aggiunge al saldo solo se l'importo è positivo e restituiscetruese l'operazione riesce,falsealtrimenti - Un metodo pubblico
Withdraw(decimal amount)che sottrae dal saldo solo se l'importo è positivo e non supera il saldo corrente, restituendotruese l'operazione riesce,falsealtrimenti - Un metodo pubblico
CanAfford(decimal amount)che restituiscetruese il saldo è maggiore o uguale all'importo,falsealtrimenti - Un metodo pubblico
GetStatement()che usa internamente il metodo privatoFormatBalance()e restituisce"Current balance: {formatted balance}"
Program.cs: nel tuo file principale, crea unWalleted esegui una serie di transazioni usando i valori di input. Mostra come il portafoglio protegge il proprio stato interno, offrendo comunque funzionalità utili tramite la sua interfaccia pubblica.
Riceverai tre input:
- Importo del deposito iniziale (decimal)
- Importo del prelievo da tentare (decimal)
- Importo per cui verificare la disponibilità (decimal)
Stampa l'output in questo formato:
Deposit {amount}: {True/False}
{GetStatement() result}
Withdraw {amount}: {True/False}
{GetStatement() result}
Can afford {amount}: {True/False}Per esempio, se gli input sono 100.50, 30.25 e 80.00, l'output dovrebbe essere:
Deposit 100.50: True
Current balance: $100.50
Withdraw 30.25: True
Current balance: $70.25
Can afford 80.00: FalseL'intuizione chiave è che il codice esterno non accede mai direttamente al campo del saldo. Anche la stringa del saldo formattato viene restituita tramite un metodo pubblico che usa internamente un helper privato. Questo è l'occultamento dei dati: i dettagli di implementazione sono completamente invisibili e puoi modificare il modo in cui il saldo viene memorizzato o formattato senza compromettere il codice che usa il tuo portafoglio!
Provalo tu
using System;
using Finance;
class Program
{
public static void Main(string[] args)
{
// Leggi i valori di input
decimal depositAmount = Convert.ToDecimal(Console.ReadLine());
decimal withdrawAmount = Convert.ToDecimal(Console.ReadLine());
decimal checkAmount = Convert.ToDecimal(Console.ReadLine());
// TODO: Crea un'istanza di Wallet
// TODO: Effettua un deposito e stampa il risultato nel formato: "Deposit {amount}: {True/False}"
// TODO: Stampa l'estratto conto usando GetStatement()
// TODO: Effettua un prelievo e stampa il risultato nel formato: "Withdraw {amount}: {True/False}"
// TODO: Stampa l'estratto conto usando GetStatement()
// TODO: Verifica se l'importo è disponibile e stampa il risultato nel formato: "Can afford {amount}: {True/False}"
}
}
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