Refatoração de Código: Encadear Construtores
(2497)
CategoriasAndroid, Design, Protótipo
AutorVinÃcius Thiengo
VÃdeo aulas186
Tempo15 horas
ExercÃciosSim
CertificadoSim
CategoriaEngenharia de Software
Autor(es)Vaughn Vernon
EditoraAlta Books
Edição1ª
Ano2024
Páginas160
Tudo bem?
Neste artigo continuaremos a série de conteúdos falando sobre refatoração de código.
Aqui, mais especificamente, sobre o método de refatoração Encadear Construtores, que por sinal é bem simples e útil.
Apesar de estar na categoria Android do Blog, os artigos dessa série são úteis para qualquer linguagem de programação sendo utilizada junto ao paradigma de programação orientação a objetos.
Antes de prosseguir, não esqueça de se inscrever na 📫 lista de e-mails do Blog para receber em primeira mão todos os conteúdos exclusivos sobre desenvolvimento e codificação limpa.
A seguir os tópicos que abordaremos em artigo:
Motivação
O objetivo desse método de refatoração é diminuir (ou eliminar) código duplicado dentro de construtores de uma classe. O problema de código duplicado é o principal motivo para a existência de vários padres de projeto.
O problema é realmente descoberto no momento da atualização do software.
Um simples exemplo em texto, do problema. Segue:
Foi adicionado mais um atributo a classe e um dos construtores dela trabalha a inicialização desse novo atributo.
Porém as outras sobrecargas de construtores, com código repetido, não passaram pela atualização e o novo atributo não é referenciado nesses.
O que temos agora é um provável bug, pois caso um outro construtor seja utilizado para criar a instância da classe e logo depois um método que utiliza esse novo atributo seja invocado, teremos no mínimo uma saída de dados inconsistente.
Código de exemplo
Vamos utilizar um software de empréstimo bancário, mais precisamente parte do código desse software.
Com esse software é possível criar instâncias de Empréstimo que podem trabalhar de diferentes maneiras dependendo do construtor utilizado.
Essas maneiras distintas de trabalho representam os possíveis tipos de empréstimos da entidade financeira.
Abaixo o código da classe Emprestimo:
public class Emprestimo {
private Estrategia estrategia;
private double obrigacao;
private double paraSaldar;
private int escalaDeRisco;
private Date vencimento;
private Date expiracao;
public Emprestimo(
double obrigacao,
int escalaDeRisco,
Date vencimento ){
this.obrigacao = obrigacao;
this.escalaDeRisco = escalaDeRisco;
this.vencimento = vencimento;
}
public Emprestimo(
double obrigacao,
int escalaDeRisco,
Date vencimento,
Date expiracao ){
this.obrigacao = obrigacao;
this.escalaDeRisco = escalaDeRisco;
this.vencimento = vencimento;
this.expiracao = expiracao;
}
public Emprestimo(
double obrigacao,
double paraSaldar,
int escalaDeRisco,
Date vencimento,
Date expiracao ){
this.obrigacao = obrigacao;
this.paraSaldar = paraSaldar;
this.escalaDeRisco = escalaDeRisco;
this.vencimento = vencimento;
this.expiracao = expiracao;
}
public Emprestimo(
Estrategia estrategia,
double obrigacao,
int escalaDeRisco,
Date vencimento, Date expiracao ){
this.estrategia = estrategia;
this.obrigacao = obrigacao;
this.escalaDeRisco = escalaDeRisco;
this.vencimento = vencimento;
this.expiracao = expiracao;
}
public Emprestimo(
Estrategia estrategia,
double obrigacao,
double paraSaldar,
int escalaDeRisco,
Date vencimento,
Date expiracao ){
this.estrategia = estrategia;
this.obrigacao = obrigacao;
this.paraSaldar = paraSaldar;
this.escalaDeRisco = escalaDeRisco;
this.vencimento = vencimento;
this.expiracao = expiracao;
}
/* TODO */
}
Note que vamos utilizar somente a parte necessária do código para a explicação do método de refatoração, por isso os "…" logo no final da classe.
Mecânica
O primeiro passo é encontrar o construtor que tem um número de atributos que atenda a todos os outros construtores.
Mesmo que em alguns casos os valores null, 0 ou false (valores padrões em objetos e primitivos no Java) tenham de ser fornecidos por esses outros construtores.
Curiosidade:
Se você buscar em outras literaturas conteúdo sobre esse método de refatoração logo vai perceber que ele não tem esse primeiro passo de diretamente buscar o construtor correto.
Na verdade o recomendado em outras fontes é ir verificando de dois em dois construtores para então ajustar o código dos construtores por completo.
Aqui optei por simplificar o processo, pois o resultado final será o mesmo: ter um construtor que atenda a todos os outros.
Caso o construtor que tenha todos os parâmetros de entrada necessários para atender aos outros não exista, então crie um.
Porém coloque o modificador de acesso dele como private (esse passo do private é opcional e será explicado mais a frente no decorrer desse artigo).
Note que somente no caso da criação de um novo construtor base é que ele já inicia como private, se esse construtor já existisse, ainda seria necessário a aplicação do passo dois do método de refatoração deste artigo.
Ainda no primeiro passo, depois de encontrado ou criado o construtor base, utilize ele nos outros construtores para ao menos ser o algoritmo responsável pela inicialização das variáveis de instância.
Em nosso projeto de exemplo, o último construtor apresentado no código pode ser utilizado por todos os outros construtores.
Logo, aplicando o método de refatoração proposto aqui nós temos o seguinte novo código para a classe Emprestimo:
public class Emprestimo {
private Estrategia estrategia;
private double obrigacao;
private double paraSaldar;
private int escalaDeRisco;
private Date vencimento;
private Date expiracao;
public Emprestimo(
double obrigacao,
int escalaDeRisco,
Date vencimento ){
this( null, obrigacao, 0.0, escalaDeRisco, vencimento, null );
}
public Emprestimo(
double obrigacao,
int escalaDeRisco,
Date vencimento,
Date expiracao ){
this( null, obrigacao, 0.0, escalaDeRisco, vencimento, expiracao );
}
public Emprestimo(
double obrigacao,
double paraSaldar,
int escalaDeRisco,
Date vencimento,
Date expiracao ){
this( null, obrigacao, paraSaldar, escalaDeRisco, vencimento, expiracao );
}
public Emprestimo(
Estrategia estrategia,
double obrigacao,
int escalaDeRisco,
Date vencimento,
Date expiracao ){
this( estrategia, obrigacao, 0.0, escalaDeRisco, vencimento, expiracao );
}
public Emprestimo(
Estrategia estrategia,
double obrigacao,
double paraSaldar,
int escalaDeRisco,
Date vencimento,
Date expiracao ){
this.estrategia = estrategia;
this.obrigacao = obrigacao;
this.paraSaldar = paraSaldar;
this.escalaDeRisco = escalaDeRisco;
this.vencimento = vencimento;
this.expiracao = expiracao;
}
/* TODO */
}
O segundo passo é referente a verificação das chamadas de códigos clientes a esses construtores, mais precisamente verificar se há ou não chamadas ao nosso construtor base (o que é utilizado por todos os outros construtores).
Caso não encontrada alguma chamada a esse construtor, coloque o modificador de acesso a ele como private.
Por que o private?
Colocar entidades de uma classe como private alivia em muito o processo de refatoração do projeto de software.
Tendo em mente que mesmo utilizando IDEs sofisticadas, as entidades com tipo de acesso private lhe permitem evitar uma busca abrangente em todo o projeto para poder saber se será trivial ou não o passo de mover o atributo ou método para outra parte do software.
Kent Beck em "Padrões de Implementação" indica que no desenvolvimento do software devemos ir aumentando a abrangência do modificador de acesso das entidades do projeto somente quando forem necessárias.
Ou seja, todas começam em private, logo depois, surgindo a necessidade, verificar se protected é o suficiente para suprir tal necessidade.
E assim por diante até chegar ao modificador de acesso public, o mais abrangente.
Com isso aplicamos o método de refatoração proposto. Para completar a refatoração da classe coloque intenção na criação de objetos, veja o artigo Substituir Construtores Por Métodos de Criação, para entender essa refatoração.
Conclusão
Como já informado:
Código duplicado é um problema tão sério que a maior parte dos padrões de projeto existem devido a ele.
Não existe um único padrão ou qualquer outra estratégia isolada que consiga evitar de forma definitiva os códigos duplicados de um projeto de software.
Na verdade são cooperações entre técnicas de código limpo que vão permitir esse "de forma definitiva" para o fim dos códigos repetidos de seu algoritmo se tornar algo real.
Uma dessas técnicas, simples de entender e de utilizar, é o método de refatoração Encadear Construtores, logo, o utilize sempre que enxergado o padrão de código que permite a aplicação dele.
Pode ser que haja um outro construtor de seu projeto que tenha um código muito diferente e que não seja possível reaproveitar nada.
Não há problemas, utilize a técnica aqui com os construtores que seja possível a implementação dela.
A ideia está em diminuir ao máximo o número de códigos duplicados.
Então é isso.
Por fim, não deixe de se inscrever na 📩 lista de e-mails do Blog para receber os conteúdos de desenvolvimento e codificação limpa exclusivos, em primeira mão e também...
... na versão em PDF (versão liberada somente para os inscritos da lista de e-mails).
Abraço.
Outros artigos da série
Listo abaixo todos os métodos de refatoração já apresentados nesta série do Blog sobre "Código Limpo":
- Internalizar Singleton;
- Mover Embelezamento Para Decorator;
- Substituir Condicionais que Alteram Estado por State;
- Introduzir Objeto Nulo;
- Unificar Interfaces Com Adapter;
- Extrair Adapter;
- Mover Conhecimento de Criação Para Factory;
- Substituir Notificações Hard-Coded Por Observer;
- Substituir Código de Tipo Por Classe;
- Extrair Parâmetro;
- Unificar Interfaces;
- Limitar Instanciação Com Singleton;
- Mover Acumulação Para Parâmetro Coletor;
- Compor Method;
- Formar Template Method;
- Substituir Lógica Condicional Por Strategy;
- Introduzir Criação Polimórfica com Factory Method;
- Encapsular Classes Com Factory;
- Substituir Construtores Por Métodos de Criação.
Comentários Facebook