Refatoração de Código: Unificar Interfaces
(1933)
CategoriasAndroid, Design, Protótipo
AutorVinÃcius Thiengo
VÃdeo aulas186
Tempo15 horas
ExercÃciosSim
CertificadoSim
CategoriaEngenharia de Software
Autor(es)Kent Beck
EditoraNovatec
Edição1ª
Ano2024
Páginas112
Opa, blz?
Nesse artigo continuamos com a série Refatoração de Código para se tornar um developer de alto desempenho, dessa vez abordando o método de refatoração Unificar Interfaces.
Já lhe adianto que se em alguma outra refatoração foi informado que ela era a menor, na verdade, essa é a menor.
Antes de prosseguir informo que no final do artigo tem os links de todos os outros métodos de refatoração já apresentados até aqui, nessa série, e que eles podem ser utilizados em qualquer linguagem que seja possível trabalhar no paradigma orientado a objetos. Alguns métodos podem ser utilizados até mesmo no paradigma procedural.
Tópicos presentes no artigo:
Motivação
Em seu código há uma hierarquia de classes onde a superclasse, apesar de ter implementado nela alguns métodos e atributos comuns as subclasses, ainda não trabalha de forma polimórfica, pois as subclasses ainda têm trechos com as próprias implementações. Trabalhar com polimorfismo é também ter a mesma interface (métodos e atributos públicos) das subclasses.
Note que interface aqui implica em métodos e atributos com tipo de acesso public e não a Interface estrutura de linguagem.
Código de exemplo
O código desse artigo é uma simples hierarquia do mundo animal. Para permitir que parte da lógica do projeto seja alterada para trabalhar com o polimorfismo, vamos aplicar o método de refatoração na superclasse a seguir:
public abstract class Animal {
public abstract void andar();
public abstract void comer();
}
Abaixo a classe Formiga que herda de Animal e implementa os métodos obrigatórios:
public class Formiga extends Animal {
@Override
public void andar() {
...
}
@Override
public void comer() {
...
}
public double forcaGancho(){
...
}
}
E ainda temos a classe Cachorro que também herda de Animal:
public class Cachorro extends Animal {
@Override
public void andar() {
...
}
@Override
public void comer() {
...
}
public void latir(){
...
}
}
Nosso objetivo é permitir que a classe Animal tenha uma interface comum quanto as suas subclasses para que seja possível em um array de Animal, por exemplo, realizar o processamento polimórfico das instâncias sem necessidade de identificação de tipo, independente dos métodos invocados.
Mecânica
O método de refatoração proposto aqui, como já informado: é bem simples. Temos apenas um passo a ser implementado. Pode acreditar.
Vamos buscar métodos públicos, nas subclasses, que estejam ausentes em na superclasse sendo refatorada. Na hierarquia do projeto de exemplo temos os métodos forcaGancho() que está em Formiga e latir() que está em Cachorro.
Esses métodos ausentes terão cópias nulas (ou conteúdo vazio) em nossa superclasse Animal.
Cópias nulas?
Sim, eles não terão comportamento definido, serão vazios, pois com o objetivo de ter uma interface comum e sabendo que eles não são comuns na hierarquia de classes, não devemos forçar uma implementação comum as subclasses, dessa forma apenas deixamos os métodos vazios. Caso algum deles tenha retorno, apenas retornamos o dado padrão para o tipo de retorno, por exemplo: null para String e 0 para int.
Segue nova versão de Animal, depois de realizar a cópia de forcaGancho():
public abstract class Animal {
public abstract void andar();
public abstract void comer();
public double forcaGancho(){
return( 0 );
}
}
Perceba que como retorno do método colocamos o valor 0, pois em nosso caso a implementação é em Java, e para tipos primitivos numéricos o 0 é o valor padrão. Lembrando que esse retorno de valor padrão, para um método que tem retorno, é equivalente a uma implementação vazia.
Note que, antes do código acima, foi informado que realizamos uma "cópia" e não uma remoção, pois a classe Formiga mantém a implementação de forcaGancho().
Esse foi o primeiro e único passo. O que devemos fazer agora é aplicar o mesmo para todos os outros métodos públicos encontrados nas subclasses e que não têm uma referência na superclasse. Logo, ainda temos que aplicar o mesmo passo de refatoração para o método latir() de Cachorro:
public abstract class Animal {
public abstract void andar();
public abstract void comer();
public double forcaGancho(){
return( 0 );
}
public void latir(){}
}
Como latir() não tem retorno, literalmente não precisamos fazer nada no conteúdo dele.
Dessa forma, um código cliente que utiliza uma coleção de animais poderia seguramente trabalhar com a classe Animal e chamar todos os métodos sem necessidade de identificação de tipo de classe para saber se pode ou não invocar determinado método:
...
Animal[] animais = new Animal[2];
animais[0] = new Cachorro();
animais[1] = new Formiga();
for( Animal animal : animais ){
animal.andar();
animal.comer();
animal.latir();
animal.forcaGancho();
}
...
Com isso finalizamos o método de refatoração proposto aqui.
Você provavelmente deve estar se perguntando: somente vamos utilizá-lo quando for necessária a aplicação de polimorfismo?
Não. Quando for necessário que uma classe tenha uma interface única em relação a outras classes (não necessariamente subclasses) é que se aplica o método de refatoração Unificar Interfaces.
Somente com classes (superclasses) conseguimos essa interface unificada?
Não. O método pode ser aplicado para Interfaces também, mas no caso de Interface a implementação por parte das classes concretas será inevitável.
Conclusão
Polimorfismo via herança tem suas vantagens (e desvantagens), a principal delas é deixar o código limpo quando a herança é aplicada corretamente, ou seja, entre classes relacionadas.
Apesar de alguns métodos definidos na classe base não serem requeridos por algumas subclasses, depois da aplicação do método desse artigo. Pode ser que esse modelo de código melhor se encaixe para a lógica de negócio que seu projeto tem de utilizar.
Nesse contexto, não deixe de aplicar essa melhoria por causa de alguns métodos extras na superclasse (ou Interface). As refatorações, muitas vezes, vão melhorar o código para uma próxima refatoração.
Outros artigos da série
Abaixo listo os artigos dessa série, com outras refatorações, que já foram liberados:
Mover Embelezamento Para Decorator
Substituir Condicionais que Alteram Estado por State
Unificar Interfaces Com Adapter
Mover Conhecimento de Criação Para Factory
Substituir Notificações Hard-Coded Por Observer
Substituir Código de Tipo Por Classe
Limitar Instanciação Com Singleton
Mover Acumulação Para Parâmetro Coletor
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
Fontes
Vlw.
Comentários Facebook