Refatoração de Código: Substituir Lógica Condicional Por Strategy

Receba em primeira mão, e com prioridade, os conteúdos Android exclusivos do Blog. Você receberá um email de confirmação. Somente depois de confirma-lo é que poderei lhe enviar os conteúdos exclusivos.

Email inválido.
Blog /Android /Refatoração de Código: Substituir Lógica Condicional Por Strategy

Refatoração de Código: Substituir Lógica Condicional Por Strategy

Vinícius Thiengo
(1760) (1)
Go-ahead
"Foque em ser produtivo ao invés de ser oculpado."
Tim Ferris
Kotlin Android
Capa do livro Desenvolvedor Kotlin Android - Bibliotecas para o dia a dia
TítuloDesenvolvedor Kotlin Android - Bibliotecas para o dia a dia
CategoriasAndroid, Kotlin
AutorVinícius Thiengo
Edição
Capítulos19
Páginas1035
Acessar Livro
Treinamento Oficial
Android: Prototipagem Profissional de Aplicativos
CursoAndroid: Prototipagem Profissional de Aplicativos
CategoriaAndroid
InstrutorVinícius Thiengo
NívelTodos os níveis
Vídeo aulas186
PlataformaUdemy
Acessar Curso
Receitas Android
Capa do livro Receitas Para Desenvolvedores Android
TítuloReceitas Para Desenvolvedores Android
CategoriaDesenvolvimento Android
AutorVinícius Thiengo
Edição
Ano2017
Capítulos20
Páginas936
Acessar Livro
Código Limpo
Capa do livro Refatorando Para Programas Limpos
TítuloRefatorando Para Programas Limpos
CategoriaEngenharia de Software
AutorVinícius Thiengo
Edição
Ano2017
Capítulos46
Páginas599
Acessar Livro
Quer aprender a programar para Android? Acesse abaixo o curso gratuito no Blog.
Conteúdo Exclusivo
Receba em primeira mão, e com prioridade, os conteúdos Android exclusivos do Blog.
Email inválido

Opa, blz?

Dando continuidade a série Refatoração de Código, para termos um código mais limpo. Nesse artigo vamos falar da aplicação do padrão Strategy por meio do método de refatoração Substituir Lógica Condicional por Strategy.

Antes de prosseguir lembro que os artigos dessa série são úteis para developers de qualquer linguagem de programação, específicamente para aqueles que programam no paradigma orientado a objetos.

Note que para o entendimento do método abaixo ser possível, é essencial que você conheça antes o padrão Strategy. Caso ainda não o conheça, acesse o artigo que tem aqui no Blog sobre esse design pattern:

Padrão de Projeto: Strategy (Estratégia)

Tópicos presentes no artigo:

Motivação

Devido a velocidade necessária para terminarmos nossos projetos pode ser inteligente passar por alguns pontos sem a aplicação de padrões que minimizariam a dor de cabeça quando a volta ao código fosse necessária. Não somente diminuiriam a dor como também diminuiriam a repetição de código e colocaria mais intenção em nossas lógicas de negócio dispensando comentários em certos trechos.

Em casos onde há condicionais complexas para a execução de scripts específicos, muitas vezes de acordo com o tipo de uma variável de instância da classe. Nesse contexto podemos aplicar uma refatoração onde colocaríamos as lógicas de execução desses condicionais em métodos específicos dentro da própria classe onde se encontra o método com condicionais complexos.

Porém essa abordagem pode sobrecarregar nossa classe colocando uma série de métodos pequenos e que poderiam ser reutilizados em outras classes do domínio do problema.

Uma outra abordagem é a utilização de polimorfismo, onde utilizaríamos subclasses para trabalhar os métodos específicos. A problemática aqui é quando somente poucos métodos, muitas vezes somente um, devem ter comportamento especifico, dessa forma estamos sobrecarregando o domínio do problema de nosso projeto além de termos de modificar todo o código que trabalhava diretamente com a classe que vai se tornar superclasse.

A solução que nos resta é a utilização do padrão Strategy que permite que criemos classes especificas para cada trecho de código que está entre as condicionais complexas, eliminando assim as condicionais e colocando intenção no código facilitando a leitura dele, além de permitir a reutilização desse código por outras classes do projeto e não somente a classe de origem do problema.

Código de exemplo

No exemplo a seguir vamos utilizar trechos de um código bancário, mais especificamente o trecho necessário para compreender a refatoração proposta nesse artigo.

A classe Emprestimo do código a seguir é a classe que será refatorada. Nela há um método onde é definido o cálculo de empréstimo bancário a ser utilizado. O resultado desse cálculo é retornado depois de passar por alguns testes complexos com vários condicionais.

Os cálculos são específicos para empréstimos do tipo: tempo limitado, recorrente e linha sugerida. Segue trecho do código do método capital() na classe Emprestimo:

public class Emprestimo {
...
public double capital(){

if( expiracao == null && maturidade != null ){ /* TEMPO LIMITE */
return( comprometimento * duracao() * fatorRisco() );
}
else if( expiracao != null && maturidade == null ){

if( getPorcentagemNaoUtilizada() != 1.0 ){ /* LINHA SUGERIDA */
return( comprometimento * getPorcentagemNaoUtilizada() * duracao() * fatorRisco() );
}
else{ /* RECORRENTE */
return(
(proeminenteQuantidadeRisco() * duracao() * fatorRisco())
+
(quantidadeRiscoNaoUtilizado() * duracao() * fatorRiscoNaoUtilizado())
);
}
}
return( 0.0 );
}
...
}

 

Note que no código acima não é trivial o entendimento de qual condicional é relativa a qual método de empréstimo, quase que impossível saber o tipo de empréstimo se o código não for refatorado ou comentado.

É importante que você não foque no cálculo e nas variáveis e métodos sendo utilizados. Muito do código de Emprestimo vai ser ocultado. O que tem de entender é como colocar o padrão por meio do método de refatoração proposto, movendo a complexidade das condicionais de escolha de cálculo para classes Strategy.

Abaixo o construtor e os métodos de criação de instância da classe Emprestimo. Os métodos de criação são úteis para que o código cliente saiba quando criar uma instância de Emprestimo com comportamento de: tempo limite, recorrente ou linha sugerida. Segue código:

public class Emprestimo {

private Emprestimo(
double comprometimento,
double proeminente,
Date inicio,
Date expiracao,
Date maturidade,
int classificacaoRisco ){
...
}

public static Emprestimo criarTempoLimitado(...){
...
}

public static Emprestimo criarRecorrente(...){
...
}

public static Emprestimo criarLinhaSugerida(...){
...
}
...
}

 

Os métodos de criação apresentados acima são conseguidos por meio do método de refatoração Substituir Construtores Por Métodos de Criação.

Abaixo estão os métodos auxiliares ao método capital():

public class Emprestimo {
...
private double proeminenteQuantidadeRisco(){
return( proeminente );
}

private double quantidadeRiscoNaoUtilizado(){
return( comprometimento - proeminente );
}

public double duracao(){

if( expiracao == null && maturidade != null ){

return( pesoDuracaoMedia() );
}
else if( expiracao != null && maturidade == null ){

return( anosPara( expiracao ) );
}
return( 0.0 );
}

private double pesoDuracaoMedia(){

double duracao = 0.0;
double pesoMedio = 0.0;
double somaPagamentos = 0.0;
Iterator pagamentosEmprestimo = pagamentos.iterator();

while( pagamentosEmprestimo.hasNext() ){

Pagamento pagamento = (Pagamento) pagamentosEmprestimo.next();
somaPagamentos += pagamento.quantidade();
pesoMedio += anosPara( pagamento.data() ) * pagamento.quantidade();
}

if( comprometimento != 0.0 ){
duracao = pesoMedio / somaPagamentos;
}
return( duracao );
}

private double anosPara( Date dataFinal ){

Date dataInicio = (hoje == null ? inicio : hoje);
return(
((dataFinal.getTime() - dataInicio.getTime()) / MILISSEGUNDOS_POR_DIA) / DIAS_POR_ANO
);
}

private double fatorRisco(){
return( FatorRisco.getFatores().paraClassificacao( fatorRisco ) );
}

private double fatorRiscoNaoUtilizado(){
return( FatorRiscoNaoUtilizado.getFatores().paraClassificacao( fatorRisco ) );
}
...
}

 

Com o código de exemplo apresentado podemos seguir para a refatoração.

Mecânica

O primeiro passo é criar uma classe representando a ConcreteStrategy do padrão, onde o nome dela será de acordo com o comportamento que o padrão Strategy terá de encapsular por meio de classes de estratégia.

Em nosso caso será CapitalStrategy, pois é o método capital() que contém a complexidade que queremos remover. O Strategy no final do nome da classe é opcional, mas indicado para ser fácil a identificação do tipo de padrão sendo implementado, além de passar a característica de linguagem universal, no código, ganho comum na utilização de padrões de projeto. Segue algoritmo da nova classe:

public class CapitalStrategy {
// TODO
}

 

Nosso segundo passo é mover o método capital() de Emprestimo para CapitalStrategy. Junto devemos mover todos os métodos e atributos que são utilizados somente no método capital(). Logo nossa nova classe segue como:

public class CapitalStrategy {
...

/* COPIADO DE EMPRESTIMO */
public double capital(){

if( expiracao == null && maturidade != null ){ /* TEMPO LIMITE */
return( comprometimento * duracao() * fatorRisco() );
}
else if( expiracao != null && maturidade == null ){

if( getPorcentagemNaoUtilizada() != 1.0 ){ /* LINHA SUGERIDA */
return( comprometimento * getPorcentagemNaoUtilizada() * duracao() * fatorRisco() );
}
else{ /* RECORRENTE */
return(
(proeminenteQuantidadeRisco() * duracao() * fatorRisco())
+
(quantidadeRiscoNaoUtilizado() * duracao() * fatorRiscoNaoUtilizado())
);
}
}
return( 0.0 );
}

/* MOVIDO DE EMPRESTIMO */
private double fatorRisco(){
return( FatorRisco.getFatores().paraClassificacao( fatorRisco ) );
}

/* MOVIDO DE EMPRESTIMO */
private double fatorRiscoNaoUtilizado(){
return( FatorRiscoNaoUtilizado.getFatores().paraClassificacao( fatorRisco ) );
}
}

 

Mesmo que não tenha aqui todo o código da classe Emprestimo, pode assumir seguramente que esses são os métodos que somente são utilizados dentro do método capital(). As variáveis de instancia deles também ou são somente utilizados neles ou no método capital().

Os outros métodos não podem ser movidos para CapitalStrategy pois dependem de entidades que não são somente utilizadas diretamente ou indiretamente pelo método capital().

Note que a classe Emprestimo ainda tem o método capital(), porém agora esse método delega o cálculo para uma instância de CapitalStrategy.

Antes de mostrar como ficou o método capital() em Emprestimo, devemos definir como acessar os métodos e atributos de Emprestimo que não foram passíveis de mudança de classe. Temos mais de uma estratégia, são elas:

  • Passar a instância de Emprestimo como parâmetro e então alterar a classe Emprestimo a ponto de ter de modificar a visibilidade de métodos que antes somente podiam ser acessados dentro da classe (os private) e também adicionar métodos getters para encapsular o acesso a atributos private. O ponto negativo aqui é a modificação da classe Emprestimo;
  • Passar todas as entidades necessárias em CapitalStrategy por meio do construtor dele ou por métodos de atribuição, setters. O ponto negativo aqui é quando há muitos dados a serem passados como argumento além de termos de mover ainda mais código de Emprestimo para CapitalStrategy devido aos métodos que ainda estão em Emprestimo e não são de uso exclusivo de capital();
  • Utilizar um objeto de uma classe extra somente para conter os valores dos atributos de Emprestimo que seriam necessários em CapitalStrategy. O ponto negativo é ter de criar uma nova classe no domínio do problema além de não poder utilizar os métodos de Emprestimo sem movê-los para a classe CapitalStrategy;

Devido aos métodos que não são de uso exclusivo do método capital() vamos ficar com a primeira opção, passar uma instância de Emprestimo como referência em CapitalStrategy. Logo nossa classe estratégia de capital agora tem a seguinte estrutura:

public class CapitalStrategy {
...
public double capital( Emprestimo emp ){

if( emp.getExpiracao() == null && emp.getMaturidade() != null ){ /* TEMPO LIMITE */

return( emp.getComprometimento() * emp.duracao() * fatorRisco( emp ) );
}
else if( emp.getExpiracao() != null && emp.getMaturidade() == null ){

if( emp.getPorcentagemNaoUtilizada() != 1.0 ){ /* LINHA SUGERIDA */

return( emp.getComprometimento() * emp.getPorcentagemNaoUtilizada() * emp.duracao() * fatorRisco( emp ) );
}
else{ /* RECORRENTE */
return(
(emp.proeminenteQuantidadeRisco() * emp.duracao() * fatorRisco( emp ))
+
(emp.quantidadeRiscoNaoUtilizado() * emp.duracao() * fatorRiscoNaoUtilizado( emp ))
);
}
}
return( 0.0 );
}

private double fatorRisco( Emprestimo emp ){
return( FatorRisco.getFatores().paraClassificacao( emp.getClassificacaoRisco() ) );
}

private double fatorRiscoNaoUtilizado( Emprestimo emp ){
return( FatorRiscoNaoUtilizado.getFatores().paraClassificacao( emp.getClassificacaoRisco() ) );
}
}

 

Lembrando que como passamos uma instância de Emprestimo para o método capital() devemos modificar (ou adicionar) algumas entidades em Emprestimo, logo a classe agora tem a seguinte estrutura:

public class Emprestimo {
...
public double capital(){
return( new CapitalStrategy().capital( this ) );
}

public Date getExpiracao(){
return( expiracao );
}

public Date getMaturidade(){
return( maturidade );
}

public double getComprometimento(){
return( comprometimento );
}

public double getPorcentagemNaoUtilizada(){
return( porcentagemNaoUtilizada );
}

public double proeminenteQuantidadeRisco(){
return( proeminente );
}

public double quantidadeRiscoNaoUtilizado(){
return( comprometimento - proeminente );
}
...
}

 

Os tipos de acesso são todos public e o método capital() somente delega o cálculo para uma instância CapitalStrategy.

Note que ainda temos métodos em Emprestimo que são utilizados somente para o cálculo de capital(), porém esses utilizam atributos de Emprestimo que não são exclusivos de uso do método capital() (note que não estou falando dos métodos do código anterior e sim de métodos como duracao(), por exemplo).

Como agora temos uma referência a Emprestimo dentro de CapitalStrategy, podemos mover esses métodos específicos para os cálculos de capital() para CapitalStrategy e então acessar os atributos de Emprestimo por meio dessa referência passada como parâmetro.

Em nossa classe CapitalStrategy vamos adicionar os métodos duracao(), pesoDuracaoMedia() e anosPara(), além das constantes utilizadas em anosPara() conforme código abaixo:

public class CapitalStrategy {
private static final int MILISSEGUNDOS_POR_DIA = 86400000;
private static final int DIAS_POR_ANO = 365;

...
public double duracao( Emprestimo emp ){

if( emp.getExpiracao() == null && emp.getMaturidade() != null ){ /* TEMPO LIMITE */

return( pesoDuracaoMedia( emp ) );
}
else if( emp.getExpiracao() != null && emp.getMaturidade() == null ){ /* RECORRENTE E LINHA SUGERIDA */

return( anosPara( emp.getExpiracao(), emp ) );
}
return( 0.0 );
}

private double pesoDuracaoMedia( Emprestimo emp ){

double duracao = 0.0;
double pesoMedio = 0.0;
double somaPagamentos = 0.0;
Iterator pagamentosEmprestimo = emp.getPagamentos().iterator();

while( pagamentosEmprestimo.hasNext() ){

Pagamento pagamento = (Pagamento) pagamentosEmprestimo.next();
somaPagamentos += pagamento.quantidade();
pesoMedio += anosPara( pagamento.data(), emp ) * pagamento.quantidade();
}

if( emp.getComprometimento() != 0.0 ){
duracao = pesoMedio / somaPagamentos;
}
return( duracao );
}

private double anosPara( Date dataFinal, Emprestimo emp ){

Date dataInicio = (emp.getHoje() == null ? emp.getInicio() : emp.getHoje());
return(
((dataFinal.getTime() - dataInicio.getTime()) / MILISSEGUNDOS_POR_DIA) / DIAS_POR_ANO
);
}
}

 

Podemos modificar nossa classe CapitalStrategy para utilizar o método duracao() local.

Se voltarmos ao código de Emprestimo, no início do exemplo é possível notar que o método duracao() apesar de ser utilizado somente pelo método capital() ele tem acesso public, logo não podemos movê-lo de Emprestimo para CapitalStrategy e sim copiá-lo, pois Emprestimo ainda terá um método de acesso público que permitirá que o código cliente acesse de forma indireta o método duracao() de CapitalStrategy.

Depois dessa refatoração nossa classe Emprestimo terá código duplicado em capital() e em duracao(), pois ambos utilizam o trecho new CapitalStrategy(). Para remover essa duplicação vamos instanciar nosso CapitalStrategy no construtor de Emprestimo e atribuir essa instância a uma variável nomeada capitalStrategy, conforme código a seguir:

public class Emprestimo {
private CapitalStrategy capitalStrategy;

private Emprestimo(
double comprometimento,
double proeminente,
Date inicio,
Date expiracao,
Date maturidade,
int classificacaoRisco ){

capitalStrategy = new CapitalStrategy();
...
}

public double capital(){
return( capitalStrategy.capital( this ) );
}

public double duracao(){
return( capitalStrategy.duracao( this ) );
}
...
}

 

Nosso terceiro passo é fazer com que a variável capitalStrategy em Emprestimo receba dados via parâmetro. Esse passo é importante para que no próximo e último passo seja possível criar e utilizar classes especificas de Strategy e a consequente eliminação da lógica condicional que ainda existe nos métodos capital() e duracao(). Segue classe Emprestimo com os criadores de instâncias definindo o valor de capitalStrategy via parâmetro do construtor principal:

public class Emprestimo {
private CapitalStrategy capitalStrategy;

private Emprestimo(
double comprometimento,
double proeminente,
Date inicio,
Date expiracao,
Date maturidade,
int classificacaoRisco,
CapitalStrategy capitalStrategy ){

this.capitalStrategy = capitalStrategy;
...
}

public static Emprestimo criarTempoLimitado(
double comprometimento,
Date inicio,
Date maturidade,
int classificacaoRisco){

return(
new Emprestimo( comprometimento, 0, inicio, null, maturidade, classificacaoRisco, new CapitalStrategy() )
);
}

public static Emprestimo criarRecorrente(
double comprometimento,
Date inicio,
Date expiracao,
int classificacaoRisco){

return(
new Emprestimo( comprometimento, 0, inicio, expiracao, null, classificacaoRisco, new CapitalStrategy() )
);
}

public static Emprestimo criarLinhaSugerida(
double comprometimento,
Date inicio,
Date expiracao,
int classificacaoRisco){

if( classificacaoRisco > 3 ){
return null;
}
Emprestimo linhaSugerida = new Emprestimo( comprometimento, 0, inicio, expiracao, null, classificacaoRisco, new CapitalStrategy() );
linhaSugerida.setPorcentagemNaoUtilizada( 0.1 );

return( linhaSugerida );
}
...
}

 

Nosso quarto e último passo é criar as classes que vão herdar de CapitalStrategy e consequentemente passarão a ser as ConcreteStrategy que representarão os cálculos dos condicionais de capital(). Logo depois algumas modificações serão feitas em CapitalStrategy e Emprestimo. Segue classe CapitalStrategyTempoLimitado:

public class CapitalStrategyTempoLimitado extends CapitalStrategy {

public double capital( Emprestimo emp ){
return( emp.getComprometimento() * duracao( emp ) * fatorRisco( emp ) );
}

public double duracao( Emprestimo emp ){
return( pesoDuracaoMedia( emp ) );
}

private double pesoDuracaoMedia( Emprestimo emp ){

double duracao = 0.0;
double pesoMedio = 0.0;
double somaPagamentos = 0.0;
Iterator pagamentosEmprestimo = emp.getPagamentos().iterator();

while( pagamentosEmprestimo.hasNext() ){

Pagamento pagamento = (Pagamento) pagamentosEmprestimo.next();
somaPagamentos += pagamento.quantidade();
pesoMedio += anosPara( pagamento.data(), emp ) * pagamento.quantidade();
}

if( emp.getComprometimento() != 0.0 ){
duracao = pesoMedio / somaPagamentos;
}
return( duracao );
}
}

 

Agora a classe CapitalStrategyLinhaSugerida:

public class CapitalStrategyLinhaSugerida extends CapitalStrategy {

public double capital( Emprestimo emp ){
return(
emp.getComprometimento() *
emp.getPorcentagemNaoUtilizada() *
duracao( emp ) *
fatorRisco( emp )
);
}
}

 

E então a classe CapitalStrategyRecorrente:

public class CapitalStrategyRecorrente extends CapitalStrategy {

public double capital( Emprestimo emp ){
return(
(emp.proeminenteQuantidadeRisco() * duracao( emp ) * fatorRisco( emp ))
+
(emp.quantidadeRiscoNaoUtilizado() * duracao( emp ) * fatorRiscoNaoUtilizado( emp ))
);
}
}

 

Agora nossa classe CapitalStartegy passa a ser a entidade Strategy apresentada no diagrama e modelo desse padrão. Podemos então realizar algumas mudanças. Ela passa a ser abstrata e alguns métodos agora com visibilidade protected, além da remoção de código de alguns desses métodos, segue nova configuração da classe:

public abstract class CapitalStrategy {
private static final int MILISSEGUNDOS_POR_DIA = 86400000;
private static final int DIAS_POR_ANO = 365;

public abstract double capital( Emprestimo emp );

protected double fatorRisco( Emprestimo emp ){
return( FatorRisco.getFatores().paraClassificacao( emp.getClassificacaoRisco() ) );
}

protected double fatorRiscoNaoUtilizado( Emprestimo emp ){
return( FatorRiscoNaoUtilizado.getFatores().paraClassificacao( emp.getClassificacaoRisco() ) );
}

public double duracao( Emprestimo emp ){
return( anosPara( emp.getExpiracao(), emp ) );
}

protected double anosPara( Date dataFinal, Emprestimo emp ){

Date dataInicio = (emp.getHoje() == null ? emp.getInicio() : emp.getHoje());
return(
((dataFinal.getTime() - dataInicio.getTime()) / MILISSEGUNDOS_POR_DIA) / DIAS_POR_ANO
);
}
}

 

Note que o método pesoDuracaoMedia() é necessário somente para CapitalStrategyTempoLimitado, logo removemos ele de CapitalStrategy e colocamos apenas na classe de referente a tempo limitado.

Agora devemos modificar os métodos de criação em Emprestimo para trabalhar com classes ConcreteStrategy especificas. Segue:

public class Emprestimo {
private CapitalStrategy capitalStrategy;

private Emprestimo(
double comprometimento,
double proeminente,
Date inicio,
Date expiracao,
Date maturidade,
int classificacaoRisco,
CapitalStrategy capitalStrategy ){

this.capitalStrategy = capitalStrategy;
...
}

public static Emprestimo criarTempoLimitado(
double comprometimento,
Date inicio,
Date maturidade,
int classificacaoRisco){

return(
new Emprestimo( comprometimento, 0, inicio, null, maturidade, classificacaoRisco, new CapitalStrategyTempoLimitado() )
);
}

public static Emprestimo criarRecorrente(
double comprometimento,
Date inicio,
Date expiracao,
int classificacaoRisco){

return(
new Emprestimo( comprometimento, 0, inicio, expiracao, null, classificacaoRisco, new CapitalStrategyRecorrente() )
);
}

public static Emprestimo criarLinhaSugerida(
double comprometimento,
Date inicio,
Date expiracao,
int classificacaoRisco){

if( classificacaoRisco > 3 ){
return null;
}
Emprestimo linhaSugerida = new Emprestimo( comprometimento, 0, inicio, expiracao, null, classificacaoRisco, new CapitalStrategyLinhaSugerida() );
linhaSugerida.setPorcentagemNaoUtilizada( 0.1 );

return( linhaSugerida );
}
...
}

 

Com isso concluímos a implementação do padrão Strategy por meio do método de refatoração Substituir Lógica Condicional por Strategy. Agora os cálculos de capital() que incluem os métodos capital() e duracao() são realizados por meio de classes de estratégia (ou ConcreteStrategy) e sem lógica condicional complexa para escolha de algoritmo.

Conclusão

O padrão Strategy alivia em muito o código do projeto quando o trabalho com herança ou com Interface nas classes de domínio do problema não ajudam como esperado. Assim conseguimos além de manter o código mais dinâmico devido a composição, a possibilidade de reuso de código ainda mais intensificada, pois os comportamentos que se tornaram classes de estratégia são fracamente acoplados com os códigos clientes.

Porém fique atento que caso tenha vários métodos com condicionais complexas, ao invés de criar uma nova família de classes Strategy estude a possibilidade de utilizar polimorfismo por meio de herança, caso contrário a sobrecarga de classes pode começar a vir devido a implementação do padrão Strategy em demasia.

Outros artigos da série

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

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

Introduzir Criação Polimórfica com Factory Method

Encapsular Classes Com Factory

Encadear Construtores

Substituir Construtores Por Métodos de Criação

Fontes

Refatoração para Padrões

Use a Cabeça! Padrões de Projetos

Vlw.

Receba em primeira mão, e com prioridade, os conteúdos Android exclusivos do Blog.
Email inválido

Relacionado

Código Limpo - Habilidades Práticas do Agile SoftwareCódigo Limpo - Habilidades Práticas do Agile SoftwareLivros
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
Utilizando BottomSheet Material Design no AndroidUtilizando BottomSheet Material Design no AndroidAndroid
Persistência Com Firebase Android - Parte 1Persistência Com Firebase Android - Parte 1Android

Compartilhar

Comentários Facebook (1)

Comentários Blog

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...