Refatoração de Código: Substituir Construtores Por Métodos de Criação

Investir em Você é Barra de Ouro a R$ 2,00. Cadastre-se e receba grátis conteúdos Android sem precedentes! Você receberá um email de confirmação. Somente depois de confirma-lo é que eu poderei lhe enviar os conteúdos semanais exclusivos. Os artigos em PDF são entregues somente para os inscritos na lista.

Email inválido.
Blog /Android /Refatoração de Código: Substituir Construtores Por Métodos de Criação

Refatoração de Código: Substituir Construtores Por Métodos de Criação

Vinícius Thiengo
(3167) (2)
Go-ahead
"O método consciente de tentativa e erro é mais bem-sucedido que o planejamento de um gênio isolado."
Peter Skillman
Prototipagem Android
Capa do curso Prototipagem Profissional de Aplicativos
TítuloAndroid: Prototipagem Profissional de Aplicativos
CategoriasAndroid, Design, Protótipo
AutorVinícius Thiengo
Vídeo aulas186
Tempo15 horas
ExercíciosSim
CertificadoSim
Acessar Curso
Quer aprender a programar para Android? Acesse abaixo o curso gratuito no Blog.
Lendo
TítuloManual de DevOps: como obter agilidade, confiabilidade e segurança em organizações tecnológicas
CategoriaEngenharia de Software
Autor(es)Gene Kim, Jez Humble, John Willis, Patrick Debois
EditoraAlta Books
Edição1ª
Ano2018
Páginas464
Conteúdo Exclusivo
Investir em Você é Barra de Ouro a R$ 2,00. Cadastre-se e receba gratuitamente conteúdos Android sem precedentes!
Email inválido

Tudo bem?

Neste artigo será apresentado um método utilizado para refatoração de código, mais precisamente o método Substituir Construtores por Métodos de Criação.

O objetivo desse método é apresentar no código a intenção da criação de uma instância com determinados tipos e quantidades de parâmetros.

Tendo em mente que ele contribui para a substituição da família de construtores sobrecarregados que podem estar presentes em classes do domínio do problema.

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 estaremos abordando em artigo:

Motivação

A real problemática na presença de família de construtores é que para o programador que desenvolveu a classe (ao menos na época em que ele desenvolveu a classe) saber o porquê da utilização de vários construtores e quais tipos de comportamentos terá o objeto criado é algo simples para ele.

Até porque foi quem desenvolveu o algoritmo.

Esse tipo de problema está presente em classes que não convém a criação de subclasses.

Pois além de evitar ainda mais classes no domínio do problema tem que a diferença entre os tipos de instâncias não existe devido aos diferentes atributos sendo utilizados e sim aos comportamentos de alguns métodos de acordo com os valores dos atributos.

O que? Não entendi nada.

Você provavelmente já deve ter ouvido falar que se uma classe apresenta mais de um comportamento ou mais de uma tarefa principal, essa classe na verdade deveria ter subclasses ou novas classes irmãs para que esses comportamentos sejam corretamente divididos.

Sim, eu concordo com isso também.

Mas algumas vezes é cabível optar por deixar os métodos (comportamentos) na mesma classe, pois assim você não infla seu projeto com classes que somente têm um único ou poucos métodos.

Um exemplo simples.

Um projeto de um jogo medieval tem uma classe Espada que tem, entre vários métodos, dois métodos que nunca podem ser utilizados ao mesmo tempo, digo, não há configuração de estado de objeto (valores dos atributos) que permita que os métodos seguintes, corteTrovao() e corteFogo(), possam ser utilizados.

Ou seja, é possível utilizar um ou o outro de acordo com os valores dos atributos.

Caso você escolhesse por separar subclasses somente por causa desses dois métodos seu projeto teria ao menos três classes para representar a classe Espada, seriam elas: 

✓ Espada;

✓ EspadaTrovao;

✓ e EspadaFogo.

Nesse caso acredito não ser uma boa escolha.

Algumas vezes é necessário, na classe, a utilização da mesma assinatura de construtor para a obtenção da instância trabalhando de maneira diferente de acordo com os valores dos atributos, esse caso é ainda mais problemático.

Pois não é possível (ao menos na maioria das linguagens, se não todas) a criação de construtores com exatamente a mesma assinatura.

O método de refatoração desse artigo vai nos auxiliar no código de exemplo logo abaixo.

Mais precisamente, vai nos auxiliar em como colocar intenção na criação de instâncias em classes onde não é viável a solução que implica na divisão da tarefa em várias outras subclasses ou classes irmãs.

Código de exemplo

A seguir é apresentada a classe Emprestimo.

Note que há uma família de construtores e que para programadores não envolvidos na criação da classe é difícil de entender qual tipo de comportamento terá a classe Emprestimo depois da utilização dos construtores:

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,
0.0,
escalaDeRisco,
vencimento,
null );
}

public Emprestimo(
double obrigacao,
int escalaDeRisco,
Date vencimento,
Date expiracao ){

this( 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;

if( estrategia == null ){

if( expiracao == null ){
this.estrategia = new EstrategiaTempoLimitado();
}
else if( vencimento == null ){
this.estrategia = new EstrategiaRecorrente();
}
else{
this.estrategia = new EstrategiaRecorrenteTempoLimitado();
}
}
}

/* TODO - METODOS CLASSE */
}

 

Note que não foram apresentados os métodos da classe, na verdade você não precisa "quebrar a cabeça" em saber o porquê do parâmetro XYZ...

... o que tem que ter em mente é que a classe apresentada acima permite a criação de instâncias dela com inúmeros comportamentos diferentes representando os tipos distintos de empréstimos que o sistema pode ter.

Aqui estaremos trabalhando com a possibilidade de criar somente os seguintes tipos de empréstimos:

  • Tempo limitado;
  • Recorrente;
  • e Recorrente com tempo limitado.

Vale lembrar que é possível sim utilizar a estratégia de criação de subclasses ou classes irmãs.

Mas no caso em que a utilização do método Substituir Construtores por Métodos de Criação permite uma implementação mais simples e sem repetição de código, essa tende a ser a solução mais viável.

Antes de iniciar o processo de refatoração devemos primeiro identificar o construtor que é utilizado como base por todos os outros construtores, mesmo quando de forma implícita (um segundo construtor encadeado chama o construtor base).

Esse construtor completo, caso não exista, deve ser criado.

Em nosso exemplo é o último construtor apresentado:

...
public Emprestimo(
Estrategia estrategia,
double obrigacao,
double paraSaldar,
int escalaDeRisco,
Date vencimento,
Date expiracao )
...

 

Note que se em seu caso cada construtor tenha um código interno diferente, lógica de negócio própria.

Nesse caso você deve aplicar a estratégia Encadear Construtores onde todos os construtores referenciam ao construtor base, deixando toda a inicialização de atributos no construtor base.

Depois desse processo de refatoração finalizado é que poderá seguir com a aplicação do método Substituir Construtores por Métodos de Criação.

Mecânica

O primeiro passo do processo de refatoração do método proposto neste artigo é descobrir ao menos um código cliente que utiliza algum dos construtores da classe Emprestimo.

No caso vamos utilizar um trecho de um código de de uma classe de testes.

Nesse trecho será criada uma instancia de Emprestimo para trabalhar como um empréstimo do tipo limitado:

...
public void testeTempoLimitadoSemPagamentos(){

Emprestimo emprestimo = new Emprestimo( obrigacao, escalaDeRisco, vencimento );
}
...

 

Logo depois vamos aplicar os métodos de refatoração Extrair Método e Mover Método.

Onde respectivamente criaremos um método que tem como código interno o retorno de uma instancia que é criada no mesmo molde (atributos com os mesmo valores) como no exemplo do código de teste acima e logo depois a definição desse método como um método publico e estático na classe Emprestimo.

Note que o método como estático é um passo opcional, porém uma boa escolha, pois não precisamos de uma instância para criar outras instâncias.

Seguindo com o código, agora temos na classe Emprestimo:

...
public static Emprestimo criarTempoLimitado(
double obrigacao,
int escalaDeRisco,
Date vencimento ){

return new Emprestimo( obrigacao, escalaDeRisco, vencimento );
}
...

 

Dessa forma o código cliente de testes ficaria da seguinte maneira:

...
public void testeTempoLimitadoSemPagamentos(){

Emprestimo emprestimo = Emprestimo.criarTempoLimitado( obrigacao, escalaDeRisco, vencimento );
}
...

 

Diferença notável: o developer que precisa utilizar a classe Emprestimo não perderá tempo estudando os construtores para saber como criar um empréstimo com estratégia de tempo limitado, já haverá um método informando sobre como obter uma instância com o comportamento desse tipo de empréstimo.

Método de refatoração Extrair Método:

Esse método de refatoração é bem simples e dispensa um artigo somente para a explicação dele.

Quando se tem um método que realiza mais de uma tarefa ou um construtor que deveria ser na verdade um método de criação, esse método de refatoração nos permiti criar outro método (ou métodos) a partir dessas condições, dividindo ainda mais o código.

Ponto positivo:

Os códigos encapsulados ficam menores e mais fáceis de entender.

Ponto negativo:

O projeto pode acabar tendo muitos outros métodos, podendo ocasionar com isso uma perda de performance na execução.

Pois cada chamada de método implica em uma serie de recursos (incluindo espaço de memória) alocados somente para aquela chamada.

Método de refatoração Mover Método:

Esse método de refatoração, como o método Extrair Método, é bem simples e dispensa a necessidade de um artigo para a explicação dele.

Esse método faz exatamente o que indica o nome.

Quando se cria um novo método partindo de uma outra refatoração, por exemplo, é possível que esse método esteja ainda sem classe ou na classe errada, logo movemos ele para o local correto no projeto.

Como somente estamos movendo algo que já foi criado, não há pontos positivos ou negativos.

O segundo passo é encontrar todas os códigos clientes ou internos a classe Emprestimo que criam uma instância dessa classe com a mesma assinatura de construtor para criar um empréstimo do tipo tempo limitado.

Encontradas essas chamadas, substitua todas pela utilização do método de criação criarTempoLimitado().

O terceiro passo é mover o construtor base para dentro do método criarTempoLimitado():

...
public static Emprestimo criarTempoLimitado(
double obrigacao,
int escalaDeRisco,
Date vencimento ){

return new Emprestimo( null, obrigacao, 0.0, escalaDeRisco, vencimento, null );
}
...

 

Logo depois devemos destruir o construtor que era responsável pela criação da instância de Emprestimo com comportamento de empréstimo de tempo limitado.

Apagar da classe o código abaixo:

...
public Emprestimo(
double obrigacao,
int escalaDeRisco,
Date vencimento ){

this( obrigacao, 0.0, escalaDeRisco, vencimento, null );
}
...

 

O quarto passo é repetir os passos de 1 a 3 para todos os outros construtores da classe sendo refatorada.

No quinto e último passo vamos permitir a instanciação de uma class Emprestimo somente dentro da própria classe.

Ou seja, a utilização do new Emprestimo() será privada.

Teremos de colocar o construtor base com modificador de acesso private:

...
private Emprestimo(
Estrategia estrategia,
double obrigacao,
double paraSaldar,
int escalaDeRisco,
Date vencimento,
Date expiracao )
...

 

Ao final da refatoração a classe Empréstimo deverá estar da seguinte forma:

public class Emprestimo {

private Estrategia estrategia;
private double obrigacao;
private double paraSaldar;
private int escalaDeRisco;
private Date vencimento;
private Date expiracao;


private 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;

if( estrategia == null ){

if( expiracao == null ){
this.estrategia = new EstrategiaTempoLimitado();
}
else if( vencimento == null ){
this.estrategia = new EstrategiaRecorrente();
}
else{
this.estrategia = new EstrategiaRecorrenteTempoLimitado();
}
}
}

public static Emprestimo criarTempoLimitado(
double obrigacao,
int escalaDeRisco,
Date vencimento ){

return new Emprestimo( null, obrigacao, 0.0, escalaDeRisco, vencimento, null );
}

public static Emprestimo criarRecorrente(
double obrigacao,
int escalaDeRisco,
Date expiracao ){

return new Emprestimo( null, obrigacao, 0.0, escalaDeRisco, null, expiracao );
}

public static Emprestimo criarRecorrenteTempoLimitado(
double obrigacao,
int escalaDeRisco,
Date vencimento,
Date expiracao ){

return new Emprestimo( null, obrigacao, 0.0, escalaDeRisco, vencimento, expiracao );
}

public static Emprestimo criar(
Estrategia estrategia,
double obrigacao,
double paraSaldar,
int escalaDeRisco,
Date vencimento,
Date expiracao ){

return new Emprestimo( estrategia, obrigacao, paraSaldar, escalaDeRisco, vencimento, expiracao );
}

/* TODO - METODOS CLASSE */
}

 

Note que ainda deixamos um método criar() onde o cliente do código terá a opção de fornecer a estratégia de empréstimo como parâmetro de entrada.

A classe Emprestimo inicial permite a criação de mais do que três comportamentos de empréstimos, mas nesse exemplo trabalhamos apenas com três, permitindo a utilização dos outros por meio do método criar().

Conclusão

Visto que há construtores (pode ser apenas dois) que não expressam o verdadeiro tipo de comportamento que será característica da instância criada.

Visto isso utilize métodos de criação para que até mesmo você, que criou o código, possa voltar e evoluí-lo sem gastar muito tempo tentando primeiro entendê-lo.

Note que a aplicação do método de refatoração Substituir Construtores por Métodos de Criação não restringe a não utilização de outros construtores públicos.

Ou seja, se a combinação de seus construtores permitir a criação de instâncias com possibilidades de 50 comportamentos diferentes, por exemplo, o que pode fazer é utilizar o método de refatoração proposto aqui para a criação de métodos que retornam instancias mais comumente utilizadas nos códigos clientes da classe refatorada.

Se você estiver utilizando linguagem de programação de tipagem dinâmica (PHP, por exemplo), ainda é possível aplicar esse método de refatoração.

Somente o passo de encadeamento de construtores que não será necessário, alias todas as partes que envolvem mais do que apenas um construtor.

No PHP não é possível ter mais do que um construtor na mesma classe.

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

Abaixo listo todos os artigos já liberados desta série sobre refatoração de código:

Fonte

Refatoração para Padrões

Investir em Você é Barra de Ouro a R$ 2,00. Cadastre-se e receba grátis conteúdos Android sem precedentes!
Email inválido

Relacionado

Engenharia de Software: Código Limpo na PráticaEngenharia de Software: Código Limpo na PráticaDesenvolvimento Web
Código Limpo - Habilidades Práticas do Agile SoftwareCódigo Limpo - Habilidades Práticas do Agile SoftwareLivros
O Codificador Limpo - Um código de conduto para programadores profissionaisO Codificador Limpo - Um código de conduto para programadores profissionaisLivros
Padrões de Implementação - Um Catálogo de Padrões Indispensável Para o Dia a Dia do ProgramadorPadrões de Implementação - Um Catálogo de Padrões Indispensável Para o Dia a Dia do ProgramadorLivros

Compartilhar

Comentários Facebook

Comentários Blog (2)

Para código / script, coloque entre [code] e [/code] para receber marcação especifica.
Forneça seu nome válido.
Forneça seu email válido.
Forneça o comentário.
Enviando, aguarde...
johnathan (1) (0)
07/03/2016
Olá Thiengo,voçê tem algum video falando sobre DownloadManager ou como baixar files(mp3,pdf,doc)
Responder
Vinícius Thiengo (0) (0)
07/03/2016
Fala Johnathan, blz?
Não tenho conteúdos sobre p DownloadManager. Encontrei dois links que podem lhe ajudar (assumindo que vc já tem acesso aos links da doc do Android), seguem:

http://blog.vogella.com/2011/06/14/android-downloadmanager-example/

http://www.mysamplecode.com/2012/09/android-downloadmanager-example.html

Sobre o download dos files, acredito que com o Retrofit 2.0 (http://www.thiengo.com.br/library-retrofit-2-no-android ) é possível tb realizar o download, terá de testar nesse formato. Abraço
Responder