Implementação de Ocultação de Dados
Parte da seção Programação Orientada a Objetos do Journey de C# da Coddy — lição 33 de 70.
A ocultação de dados vai além de apenas usar campos private. Trata-se de projetar sua classe de modo que os detalhes de implementação interna sejam completamente invisíveis para o código externo, expondo apenas o que é necessário por meio de uma interface pública limpa.
Considere uma classe que rastreia a senha de um usuário. Você não quer que ninguém acesse a senha bruta - nem mesmo para lê-la:
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();
}
}Observe que não há como recuperar a senha ou mesmo o hash. O código externo só pode definir uma senha ou verificar uma - o mecanismo de armazenamento interno está completamente oculto. O método HashPassword também é privado porque é um detalhe de implementação que pode mudar sem afetar como a classe é usada.
Essa abordagem protege sua classe contra o uso indevido e oferece a liberdade de alterar os componentes internos posteriormente. Se você decidir usar um algoritmo de hashing diferente, nenhum código externo será quebrado, pois nada dependia de como a senha era armazenada.
Desafio
FácilVamos construir um sistema de carteira segura que demonstra a verdadeira ocultação de dados. Você criará uma carteira digital onde o saldo é completamente protegido contra acesso direto - o código externo só pode depositar, sacar e verificar se as transações são possíveis, mas nunca ver ou manipular o saldo real diretamente.
Você organizará seu código em dois arquivos:
Wallet.cs: Crie uma classeWalletno namespaceFinanceque mantém seu saldo completamente oculto. A carteira deve ter:- Um campo privado para armazenar o saldo (decimal)
- Um método privado
FormatBalance()que retorna o saldo formatado como uma string de moeda como"$123.45"- este é um auxiliar interno que não deve ser exposto - Um método público
Deposit(decimal amount)que adiciona ao saldo apenas se o valor for positivo, retornandotruese for bem-sucedido,falsecaso contrário - Um método público
Withdraw(decimal amount)que subtrai do saldo apenas se o valor for positivo e não exceder o saldo atual, retornandotruese for bem-sucedido,falsecaso contrário - Um método público
CanAfford(decimal amount)que retornatruese o saldo for maior ou igual ao valor,falsecaso contrário - Um método público
GetStatement()que usa o método privadoFormatBalance()internamente e retorna"Current balance: {formatted balance}"
Program.cs: No seu arquivo principal, crie umaWallete realize uma série de transações usando valores de entrada. Mostre como a carteira protege seu estado interno enquanto ainda fornece funcionalidade útil por meio de sua interface pública.
Você receberá três entradas:
- Valor do depósito inicial (decimal)
- Valor do saque a tentar (decimal)
- Valor para verificar a capacidade de pagamento (decimal)
Imprima a saída neste formato:
Deposit {amount}: {True/False}
{GetStatement() result}
Withdraw {amount}: {True/False}
{GetStatement() result}
Can afford {amount}: {True/False}Por exemplo, se as entradas forem 100.50, 30.25 e 80.00, a saída deve ser:
Deposit 100.50: True
Current balance: $100.50
Withdraw 30.25: True
Current balance: $70.25
Can afford 80.00: FalseA ideia principal aqui é que o código externo nunca toca diretamente no campo de saldo. Mesmo a string de saldo formatada vem através de um método público que usa internamente um auxiliar privado. Isso é ocultação de dados - os detalhes da implementação são completamente invisíveis, e você está livre para alterar como o saldo é armazenado ou formatado sem quebrar nenhum código que use sua carteira!
Folha de consulta
O ocultamento de dados significa projetar classes de modo que os detalhes da implementação interna fiquem completamente invisíveis para o código externo, expondo apenas o que é necessário por meio de uma interface pública limpa.
Use campos private para armazenar dados sensíveis e fornecer acesso controlado por meio de métodos public:
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();
}
}Princípios fundamentais:
- Sem acesso direto aos dados internos (sem getters para campos sensíveis)
- Métodos auxiliares privados para detalhes de implementação
- Métodos públicos fornecem apenas operações controladas
- O mecanismo de armazenamento interno é completamente oculto
Isso protege a classe contra o uso indevido e permite alterar a implementação interna sem quebrar o código externo.
Experimente você mesmo
using System;
using Finance;
class Program
{
public static void Main(string[] args)
{
// Lê os valores de entrada
decimal depositAmount = Convert.ToDecimal(Console.ReadLine());
decimal withdrawAmount = Convert.ToDecimal(Console.ReadLine());
decimal checkAmount = Convert.ToDecimal(Console.ReadLine());
// TODO: Criar uma instância de Wallet
// TODO: Realizar o depósito e imprimir o resultado no formato: "Deposit {amount}: {True/False}"
// TODO: Imprimir o extrato usando GetStatement()
// TODO: Realizar o saque e imprimir o resultado no formato: "Withdraw {amount}: {True/False}"
// TODO: Imprimir o extrato usando GetStatement()
// TODO: Verificar a acessibilidade financeira e imprimir o resultado no formato: "Can afford {amount}: {True/False}"
}
}
Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.
Todas as lições de Programação Orientada a Objetos
1Fundamentos de POO
Arquivos ExternosNamespaces e DiretivasIntrodução a Classes e ObjetosA Palavra-chave 'this'Métodos e ParâmetrosCampos vs PropriedadesConstrutoresInicializadores de ObjetosRecapitulação - Calculadora Simples4Herança
Sintaxe Básica de Herança (:)A Palavra-chave 'base'Palavras-chave Virtual e OverrideClasses SeladasA Classe Base 'object'Recapitulação - Hierarquia de Funcionários7Recursos Avançados
Sobrecarga de OperadoresIndexadores (this[])Sobrescrita de ToString()Métodos de ExtensãoRecapitulação - Lista Personalizada10Padrões de Projeto Parte 1
Introdução aos Padrões de ProjetoSingleton Thread-SafePadrão FactoryPadrão Observer (Eventos)Padrão Strategy2Propriedades e Membros Estáticos
Propriedades AutoimplementadasPropriedades de Apenas Leitura/EscritaCampos e Métodos EstáticosClasses EstáticasMembros com Corpo de Expressão5Polimorfismo e Interfaces
Polimorfismo: Compilação vs ExecuçãoInterface vs Classe AbstrataMúltiplas InterfacesInterfaces ExplícitasUpcasting e DowncastingRecapitulação - Calculadora de Formas8Conceitos Avançados de POO
Composição sobre HerançaGenerics (Classes e Métodos)Delegates e EventosAtributos e ReflectionIDisposable e a Instrução usingFundamentos de Injeção de Dependência11Padrões de Projeto Parte 2
Padrão CommandPadrão AdapterPadrão DecoratorPadrão Template MethodPadrão StatePadrão Composite3Arquitetura de Classes
Dados de Instância vs EstáticosPalavras-chave 'readonly' e 'const'Campos de SuporteRecapitulação - Gerenciador de Conta Bancária6Encapsulamento
Modificadores de AcessoPropriedades para EncapsulamentoImplementação de Ocultação de DadosPadrões de ImutabilidadeRecapitulação - Registros de Estudantes9Argumentos Variáveis
A Palavra-chave 'params'Parâmetros OpcionaisArgumentos NomeadosSobrecarga de Métodos