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 criar um sistema de carteira segura que demonstra o verdadeiro ocultamento de dados. Você criará uma carteira digital cujo 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 visualizar ou manipular o saldo real diretamente.
Você organizará seu código em dois arquivos:
Wallet.cs: crie uma classeWalletno namespaceFinanceque mantenha 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 somente se o valor for positivo, retornandotrueem caso de sucesso efalsecaso contrário - Um método público
Withdraw(decimal amount)que subtrai do saldo somente se o valor for positivo e não exceder o saldo atual, retornandotrueem caso de sucesso efalsecaso contrário - Um método público
CanAfford(decimal amount)que retornatruese o saldo for maior ou igual ao valor, efalsecaso contrário - Um método público
GetStatement()que usa internamente o método privadoFormatBalance()e retorna"Current balance: {formatted balance}"
Program.cs: no seu arquivo principal, crie umaWallete execute uma série de transações usando valores de entrada. Mostre como a carteira protege seu estado interno e ainda oferece funcionalidades úteis por meio de sua interface pública.
Você receberá três entradas:
- Valor do depósito inicial (decimal)
- Valor do saque a ser tentado (decimal)
- Valor para verificar se pode ser pago (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 deverá ser:
Deposit 100.50: True
Current balance: $100.50
Withdraw 30.25: True
Current balance: $70.25
Can afford 80.00: FalseA principal ideia aqui é que o código externo nunca acessa diretamente o campo de saldo. Até mesmo a string de saldo formatado é obtida por meio de um método público que usa internamente um auxiliar privado. Isso é ocultamento de dados — os detalhes da implementação ficam completamente invisíveis, e você pode alterar livremente a forma como o saldo é armazenado ou formatado sem quebrar nenhum código que use sua carteira!
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étodosPratique por conta própria: Compilador de C# online