Ocultação de Informação
Parte da seção Programação Orientada a Objetos do Journey de Dart da Coddy — lição 34 de 110.
Ocultação de informações é o princípio por trás do encapsulamento - a ideia de que uma classe deve esconder seu funcionamento interno e expor apenas o que é necessário. Você aprendeu a mecânica (campos privados, getters, setters), mas o objetivo real é projetar classes que sejam fáceis de usar e difíceis de usar incorretamente.
Considere uma classe que gerencia a senha de um usuário. O armazenamento interno e a lógica de hashing devem ser completamente ocultos:
class UserAccount {
String _username;
String _passwordHash;
UserAccount(this._username, String password)
: _passwordHash = _hashPassword(password);
static String _hashPassword(String password) {
return 'hashed_$password'; // Exemplo simplificado
}
bool verifyPassword(String password) {
return _passwordHash == _hashPassword(password);
}
String get username => _username;
}O código externo nunca vê o hash da senha ou sabe como ele é armazenado. Eles simplesmente chamam verifyPassword(). Essa separação significa que você poderia alterar completamente o algoritmo de hashing sem afetar nenhum código que use esta classe.
O insight fundamental é pensar sobre sua classe de fora para dentro.
Pergunte a si mesmo: "O que alguém que utiliza esta classe realmente precisa?" Exponha apenas isso e mantenha todo o resto privado. Isso cria uma fronteira clara entre o que sua classe faz (sua interface pública) e como ela faz (sua implementação privada).
Desafio
FácilVamos construir um sistema de carteira segura que demonstra a ocultação de informações em ação. Você criará uma carteira digital que gerencia o saldo e o histórico de transações de um usuário, mantendo todos os detalhes internos sensíveis completamente ocultos do código externo.
Você organizará seu código em dois arquivos:
wallet.dart: Crie uma classeWalletque gerencie dinheiro de forma segura. A carteira deve armazenar o nome do proprietário publicamente, mas todo o resto deve estar oculto atrás de uma interface pública limpa:- O saldo interno e o log de transações devem ser privados - o código externo nunca deve ver como você armazena ou rastreia o dinheiro
- Um método privado deve lidar com o registro de transações internamente (armazenando entradas como
"Deposit: $50.0"ou"Withdrawal: $30.0") - Forneça um método público
deposit(double amount)que adiciona dinheiro (apenas se o valor for positivo) e registra a transação internamente - Forneça um método público
withdraw(double amount)que remove dinheiro apenas se houver fundos suficientes e o valor for positivo, registrando a transação internamente. Retornetruese for bem-sucedido,falsecaso contrário - Forneça um getter público
balanceque retorna o saldo atual (acesso somente leitura) - Forneça um método público
getTransactionCount()que retorna quantas transações foram registradas (sem expor a lista de transações real) - Forneça um método público
getLastTransaction()que retorna a string da transação mais recente, ou"No transactions"se nenhuma existir - Inclua um método
printSummary()que exibe o status da carteira
main.dart: Importe sua carteira e demonstre como a ocultação de informações cria uma interface limpa e segura:- Crie uma carteira para o proprietário
"Sarah" - Deposite
100.0 - Deposite
50.0 - Tente sacar
200.0e imprima"Withdrawal of 200.0: [success/failed]"com base no resultado - Saque
30.0e imprima"Withdrawal of 30.0: [success/failed]" - Chame
printSummary() - Imprima
"Transaction count: [count]" - Imprima
"Last transaction: [transaction]"
- Crie uma carteira para o proprietário
O método printSummary() deve imprimir:
=== Wallet Summary ===
Owner: [ownerName]
Balance: $[balance]Observe como o código externo pode interagir com a carteira por meio de métodos claros e objetivos, sem nunca saber como o saldo é armazenado ou como as transações são rastreadas internamente. Os detalhes de implementação estão completamente ocultos - você poderia alterar como as transações são armazenadas sem afetar nenhum código que use a carteira.
Saída esperada:
Withdrawal of 200.0: failed
Withdrawal of 30.0: success
=== Wallet Summary ===
Owner: Sarah
Balance: $120.0
Transaction count: 3
Last transaction: Withdrawal: $30.0Folha de consulta
A ocultação de informações é o princípio por trás do encapsulamento - esconder o funcionamento interno de uma classe e expor apenas o que é necessário.
Projete classes de fora para dentro: exponha apenas o que os usuários precisam, mantenha todo o resto privado. Isso cria um limite claro entre a interface pública (o que a classe faz) e a implementação privada (como ela faz).
Exemplo de ocultação de informações com um gerenciador de senhas:
class UserAccount {
String _username;
String _passwordHash;
UserAccount(this._username, String password)
: _passwordHash = _hashPassword(password);
static String _hashPassword(String password) {
return 'hashed_$password';
}
bool verifyPassword(String password) {
return _passwordHash == _hashPassword(password);
}
String get username => _username;
}O código externo nunca vê o hash da senha ou o mecanismo de armazenamento - ele apenas usa verifyPassword(). Isso permite alterar a implementação interna sem afetar o código externo.
Experimente você mesmo
import 'wallet.dart';
void main() {
// TODO: Criar uma carteira para a proprietária "Sarah"
// TODO: Depositar 100.0
// TODO: Depositar 50.0
// TODO: Tentar sacar 200.0 e imprimir o resultado
// Formato: "Withdrawal of 200.0: [success/failed]"
// TODO: Sacar 30.0 e imprimir o resultado
// Formato: "Withdrawal of 30.0: [success/failed]"
// TODO: Chamar printSummary()
// TODO: Imprimir a contagem de transações
// Formato: "Transaction count: [count]"
// TODO: Imprimir a última transação
// Formato: "Last transaction: [transaction]"
}
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 ExternosBibliotecas e ImportaçõesIntrodução à POOClasses vs ObjetosA Palavra-chave thisMétodosVariáveis de InstânciaFundamentos de ConstrutoresRecapitulação - Calculadora Simples4Null Safety
Introdução ao Null SafetyNullable vs Non-NullableOs Operadores ? e !Palavra-chave Late e Null SafetyOperadores Null-AwareNull Safety em ClassesRecapitulação - Sistema de Perfil de Usuário7Classes Abstratas e Interfaces
Classes AbstratasMétodos AbstratosInterfaces em DartInterfaces ImplícitasImplementando vs EstendendoMúltiplas InterfacesRecapitulação - Calculadora de Formas10Coleções e Generics
Visão Geral de List, Set e MapColeções Type-SafeClasses GenéricasMétodos GenéricosRestrições de GenericsIterable e IteratorRecapitulação - Armazenamento Genérico13Conceitos Avançados de POO
Composição vs HerançaMétodos de ExtensãoClasses ChamáveisClasses Seladas (Dart 3)Records (Dart 3)Patterns & Matching (3.0)Enums com Métodos16Projeto: Gerenciamento de Biblioteca
Visão Geral do ProjetoClasses Livro e Usuário2Construtores em Dart
Construtor PadrãoConstrutores NomeadosListas de InicializaçãoConstrutores ConstantesConstrutores FactoryConstrutores de RedirecionamentoRecapitulação - Shape Builder5Encapsulamento
Membros Públicos vs PrivadosA Convenção do Prefixo _Privacidade em Nível de BibliotecaAprofundamento em Getters & SettersOcultação de InformaçãoRecapitulação - Registros de Estudantes8Mixins
Introdução aos MixinsCriando MixinsUsando Múltiplos MixinsPalavra-chave on em MixinsMixin vs HerançaMixin vs InterfaceRecapitulação - Sistema Animal11Métodos Especiais
Sobrescrita de toString()Sobrescrita de hashCode & ==Interface ComparableMétodo call()Sobrescrita de noSuchMethodRecapitulação - Coleção Personalizada14Padrões de Projeto Parte 1
Introdução aos Padrões de ProjetoPadrão SingletonPadrão FactoryPadrão ObserverPadrão Strategy3Propriedades de Classe
Membros de Instância vs EstáticosCampos Final & ConstVariáveis LateMétodos e Campos EstáticosGetters e SettersRecapitulação - Gerenciador de Conta Bancária6Herança
Herança BásicaA Palavra-chave superSobrescrita de MétodoA Anotação @overrideA Palavra-chave final para ClassesConstrutores e HerançaRecapitulação - Hierarquia de Funcionários9Polimorfismo
Fundamentos do PolimorfismoPolimorfismo via InterfacesVerificação de Tipos em Tempo de ExecuçãoOs Operadores is & asPalavra-chave CovariantRecapitulação - Processador de Pagamentos12POO Assíncrona
Futures e async/awaitFundamentos de StreamsStream ControllersConstrutores AssíncronosAsync em Métodos de ClasseRecapitulação - Data Fetcher15Padrões de Projeto Parte 2
Padrão CommandPadrão AdapterPadrão DecoratorPadrão Template MethodPadrão StatePadrão CompositePadrão Repository