Ocultação de Informações
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.0Experimente 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 OOP
Arquivos externosBibliotecas e importsIntrodução à OOPClasses vs. objetosA palavra-chave thisMétodosVariáveis de instânciaNoções básicas de construtoresRevisão - Calculadora simples4Segurança contra nulos
Introdução à segurança contra nulosAnulável vs. não anulávelOs operadores ? e !Palavra-chave Late e segurança contra nulosOperadores conscientes de nulosSegurança contra nulos em classesRecapitulação — Sistema de perfil de usuário7Classes Abstratas e Interfaces
Classes AbstratasMétodos AbstratosInterfaces em DartInterfaces ImplícitasImplementação vs. ExtensãoMúltiplas InterfacesRecapitulação - Calculadora de Formas10Coleções e Genéricos
Visão geral de List, Set e MapColeções com segurança de tiposClasses genéricasMétodos genéricosRestrições genéricasIterable e IteratorRecapitulação - Armazenamento genérico13Conceitos Avançados de OOP
Composição vs. HerançaMétodos de ExtensãoClasses ChamáveisClasses Seladas (Dart 3)Registros (Dart 3)Padrões e Correspondência (3.0)Enums com Métodos16Projeto: Gerenciamento de Biblioteca
Visão Geral do ProjetoClasses de Livros e Usuários2Construtores em Dart
Construtor padrãoConstrutores nomeadosListas de inicializaçãoConstrutores constantesConstrutores factoryConstrutores de redirecionamentoRevisão - Construtor de formas5Encapsulamento
Membros Públicos vs. PrivadosConvenção do Prefixo _Privacidade no Nível da BibliotecaAprofundamento em Getters e SettersOcultação de InformaçõesRecapitulação - Registros de Alunos8Mixins
Introdução a MixinsCriando MixinsUsando vários MixinsPalavra-chave on em MixinsMixin vs HerançaMixin vs InterfaceRecapitulação - Sistema de Animais11Métodos Especiais
Sobrescrita de toString()Sobrescrita de hashCode e ==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 e ConstVariáveis LateMétodos e Campos EstáticosGetters e SettersRecapitulação - Gerenciador de Contas Bancárias6Herança
Herança BásicaA Palavra-chave superSobrescrita de MétodosA Anotação @overrideA Palavra-chave final para ClassesConstrutores e HerançaRecapitulação - Hierarquia de Funcionários9Polimorfismo
Fundamentos do polimorfismoPolimorfismo por meio de interfacesVerificação de tipos em tempo de execuçãoOs operadores is e asPalavra-chave covarianteRecapitulação — Processador de pagamentos12OOP Assíncrona
Futures e async/awaitNoções básicas de StreamsControladores de StreamConstrutores assíncronosAsync em métodos de classeRecapitulação — Buscador de dados15Padrões de Projeto — Parte 2
Padrão CommandPadrão AdapterPadrão DecoratorPadrão Template MethodPadrão StatePadrão CompositePadrão RepositoryPratique por conta própria: Compilador de Dart online