O que é encapsulamento?
No meu sistema de cadastro de livros eu preciso do nome e do preço:
public class Livro {
private final String nome;
private final double preco;
public Livro(String nome, double preco) {
this.nome = nome;
this.preco = preco;
}
//métodos
}
Para cadastrar um livro eu preciso passar as informações e enviar para o banco de dados:
Livro livro = new Livro("Java", 27.83);
Conexao conexao = pegaConexaoComOBancoDeDados();
conexao.cadastraLivro(livro);
conexao.fechaConexao();
Todas as vezes que eu quiser cadastrar um livro eu terei que instanciá-lo, pegar uma conexão, salvar o livro e fechar a conexão. Vamos supor que agora nós precisamos verificar se o livro já existe no banco e, caso exista, precisamos atualizar em vez de salvar:
Livro livro = new Livro("Java", 27.83);
Conexao conexao = pegaConexaoComOBancoDeDados();
if(!conexao.existeLivro(livro)){
conexao.cadastraLivro(livro);
} else{
conexao.atualizaLivro(livro);
}
conexao.fechaConexao();
Quanto mais procedimentos para poder salvar o livro eu precisar, maior ficará a minha rotina de salvar livros. Imagine todas as classes que precisarem salvar um livro, terão que ser atualizadas todas as vezes que houver uma mudança! É uma péssima solução... Que tal mudarmos esse procedimento de salvar o livro para um único método? Então, ficaria:
Livro livro = new Livro("Java", 27.83);
salvaLivro(livro);
public void salvaLivro(Livro livro){
Conexao conexao = pegaConexaoComOBancoDeDados();
if(!conexao.existeLivro(livro)){
conexao.cadastraLivro(livro);
} else{
conexao.atualizaLivro(livro);
}
conexao.fechaConexao();
}
Agora não precisamos saber sobre conexão ou qualquer procedimento para salvar um livro, apenas chamamos o método salvaLivro()
, enviamos o livro, e ele faz tudo por nós! Quando transformamos um procedimento que apresenta muitas regras de negócio ou rotinas complexas em um método, chamamos isso de encapsulamento. E se tivermos que fazer um backup dos livros cada vez que salvar ou atualizar? Bastaria adicionar esse trecho em um único lugar, ou seja, no método salvaLivro()
:
//continuo usando o salvaLivro() do mesmo jeito salvaLivro(livro);
public void salvaLivro(Livro livro){
//rotina para salvar livro
conexao.fazBackupDoLivro();
conexao.fechaConexao(); }
O código mudou e continuamos utilizando o método sem nenhuma preocupação se ele mudou ou não! Além disso, o código foi modificado em apenas um lugar, ou seja, não precisamos nos preocupar se vai quebrar o nosso sistema em todos os outros lugares que usam esse método! Além de ser mais elegante, torna o nosso sistema manutenível.
É sempre importante verificar em todos os pontos do código aonde é possível aplicar o encapsulamento, pois ganhamos muitos benefícios:
- Melhor manutenção de código.
- Divisão de responsabilidades.
- Reutilização de código.
E aí, gostou do encapsulamento? Está pronto para analisar o seu código e verificar aonde ele pode ser aplicado? O encapsulamento faz parte de uma das boas práticas de refatoração de código onde é apresentado detalhadamente no curso de Refatorando na prática com Java, que demonstra como fazer manutenção em um sistema com um código de qualidade utilizando as boas práticas de refatoração.
Perguntas Frequentes:
O que é encapsulamento?
Encapsulamento é um princípo de design de código, geralmente ligado a programação orientada, que nos orienta a esconder as funcionalidades e funcionamento do nosso código dentro de pequenas unidades (normalmente métodos e funções). Isso possibilita que modificações no sistema possam ser feitas de maneira mais cirurgicas, sem que uma funcionalidade esteja espalhada por diversas partes do sistema.
Quando usar encapsulamento?
Basicamente sempre, pois a interface, a forma como classes e objetos conversam um com o outro, deve sempre estar isolada da forma como executam o que se propuseram a fazer. Essa execução é a implementação do código. Como diz o livro Design patterns: programe voltado à interface, não à implementação.
O que é a quebra de encapsulamento?
É quando a implementação deu uma funcionalidade 'vaza' para diversas partes do sistema, com código em regiões, unidades, módulos ou pacotes muito diferentes. Dessa forma, sempre que precisamos modificar essa funcionalidade, necessitamos alterar diversas partes distantes do código. Um exemplo é o uso exagerado de variáveis globais: elas começam a gerar códigos espalhados que acessam e modificam essas varáiveis, um forte acoplamento, que amarra pontas que deveriam estar mais soltas.