Guia definitivo para a refatoração.

Mago Minimalista
Studio Oceano
Published in
19 min readOct 8, 2019

Este post possui um conteúdo extenso, é uma tradução e adaptação da sessão de refactoring do site: https://refactoring.guru. Por isso o dividi em 3 estruturas (Parte I, II e III). Cada item das partes II e III te levarão a uma página do site oficial traduzida explicando sobre como resolver um problema. A parte III possue 66 técnicas de refatoração e muitas delas com exemplos práticos em Java, C#, PHP, Python e TypeScript. A parte II são 24 métodos que se apropiam de uma ou mais técnicas abordadas na parte III. E por isso eu elaborei um checklist que irá te ajudar a concluir essa leitura.

[ Checklist aqui. Faça uma cópia pro seu Google Drive ].

Então vamos começar essa jornada? Boa leitura.

PARTE I

Código Limpo

Características do código limpo:

Código limpo é óbvio para outros programadores.
E não estou falando de algoritmos super sofisticados. Nomeação de variáveis ​​inadequada e classes e métodos grandes deixam o código desleixado e difícil de entender.

Código limpo não contém duplicação.
Em um código duplicado, cada vez que você precisar fazer uma alteração precisa lembrar de fazer a mesma alteração em todas as instâncias. Isso aumenta a carga cognitiva e diminui o progresso.

O código limpo contém um número mínimo de classes e possui responsabilidades bem definidas.
Menos código é menos manutenção. Menos código é menos erros. Código é responsabilidade, mantenha-o curto e simples.

O código limpo passa em todos os testes.
Você sabe que seu código está sujo quando apenas 95% dos seus testes foram aprovados. Você sabe que está ferrado ao testar a cobertura é de 0%.

Dívida técnica

A metáfora da “dívida técnica” em relação ao código impuro foi originalmente sugerida por Ward Cunningham.

Ward Cunningham

Todo mundo faz o possível para escrever um excelente código do zero. Provavelmente, não existe um programador que intencionalmente grave código impuro em detrimento do projeto. Mas em que momento o código limpo se torna impuro?

Se você obtém um empréstimo de um banco, isso permite que você faça compras mais rapidamente. Você paga mais por agilizar o processo — não apenas paga o principal, mas também os juros adicionais do empréstimo. Escusado será dizer que você pode acumular tanto interesse que a quantia excede sua receita total, impossibilitando o reembolso total.

O mesmo pode acontecer com o código. Você pode acelerar temporariamente sem escrever testes para novos recursos, mas isso diminuirá gradualmente seu progresso todos os dias até você pagar a dívida escrevendo testes.

Causas da dívida técnica

Pressão nos negócios
Às vezes, as circunstâncias comerciais podem forçá-lo a implementar os recursos antes que eles estejam completamente concluídos.

Falta de entendimento das consequências da dívida técnica

Falta de testes
As consequências podem ser catastróficas. Por exemplo, um bug de aparência inocente pode enviar um e-mail de teste estranho para milhares de clientes ou, pior ainda, liberar ou corromper um banco de dados inteiro.

Falta de documentação
Isso atrasa a introdução de novas pessoas no projeto e pode interromper o desenvolvimento se as pessoas-chave deixarem o projeto.

Falta de interação entre os membros da equipe
Se a base de conhecimento não for distribuída por toda a empresa, as pessoas acabarão trabalhando com um entendimento desatualizado dos processos e informações sobre o projeto. Essa situação pode ser exacerbada quando os desenvolvedores juniores são treinados incorretamente por seus mentores.

Refatoração atrasada
Os requisitos do projeto estão mudando constantemente e, em algum momento, pode se tornar óbvio que partes do código são obsoletas, tornaram-se complicadas e precisam ser reprojetadas para atender a novos requisitos.

Por outro lado, os programadores do projeto estão escrevendo um novo código todos os dias que funciona com as partes obsoletas. Portanto, quanto mais tempo a refatoração for adiada, mais código dependente precisará ser reformulado no futuro.

Falta de monitoramento e conformidade
Isso acontece quando todos que trabalham no projeto escrevem o código como acharem melhor (ou seja, da mesma maneira que escreveram o último projeto).

Incompetência
É quando o desenvolvedor simplesmente não sabe escrever código decente.

Quando refatorar?

Regra de Três

  1. Quando você estiver fazendo algo pela primeira vez, faça-o.
  2. Quando você estiver fazendo algo semelhante pela segunda vez, recue por ter que repetir, mas faça a mesma coisa de qualquer maneira.
  3. Quando você estiver fazendo algo pela terceira vez, comece a refatorar.

Ao adicionar um recurso

A refatoração ajuda a entender o código de outras pessoas. Se você precisar lidar com o código sujo de outra pessoa, tente refatá-lo primeiro. Código limpo é muito mais fácil de entender. Você o aprimorará não apenas para você, mas também para aqueles que o usam depois de você.

Ao corrigir um bug

Os erros no código se comportam exatamente como os da vida real: eles vivem nos lugares mais escuros e sujos do código. Limpe seu código e os erros praticamente se descobrirão.

Durante uma revisão de código

A revisão do código pode ser a última chance de organizar o código antes que ele se torne disponível ao público.

Como refatorar?

A refatoração deve ser feita como uma série de pequenas alterações, cada uma delas tornando o código existente um pouco melhor e ainda deixando o programa em boas condições de funcionamento.

Lista de verificação de refatoração feita da maneira correta

O código deve ficar mais limpo.

Se o código permanecer imundo após a refatoração … desculpe, mas você perdeu uma hora da sua vida. Tente descobrir por que isso aconteceu.

Isso acontece frequentemente quando você se afasta da refatoração com pequenas alterações e mistura várias refatorações em uma grande mudança. Portanto, é muito fácil perder a cabeça, especialmente se você tiver um limite de tempo.

Mas isso também pode acontecer ao trabalhar com código extremamente desleixado. O que quer que você melhore, o código como um todo continua sendo um desastre.

Nesse caso, vale a pena pensar em reescrever completamente partes do código. Mas antes disso, você deve ter escrito testes e reservar uma boa parte do tempo. Caso contrário, você terminará com os tipos de resultados mencionados no primeiro parágrafo.

Novas funcionalidades não devem ser criadas durante a refatoração.

Não misture refatoração e desenvolvimento direto de novos recursos. Tente separar esses processos pelo menos dentro dos limites das confirmações individuais.

Todos os testes existentes devem passar após a refatoração.

Há dois casos em que os testes podem ser interrompidos após a refatoração:

  • Você cometeu um erro durante a refatoração. Vá em frente e corrija o erro.
  • Seus testes foram de nível muito baixo. Por exemplo, você estava testando métodos particulares de classes.
  • Nesse caso, os testes são os culpados. Você pode refatorar os testes eles mesmos ou escrever um conjunto totalmente novo de testes de nível superior. Uma ótima maneira de evitar esse tipo de situação é escrever testes no estilo BDD .

PARTE II

Code Smells

São códigos que cheiram mal e estão divididos em: Bloaters, abusadores de orientação a objeto, preventores de mudanças, dispensáveis e acopladores.

1. Bloaters

Arbustos são códigos, métodos e classes que aumentaram para proporções gigantescas com as quais é difícil trabalhar. Geralmente, esses odores não surgem imediatamente, mas acumulam-se ao longo do tempo à medida que o programa evolui (e principalmente quando ninguém se esforça para erradicá-los).

A. Método Longo 🔗 Um método contém muitas linhas de código. Geralmente, qualquer método com mais de dez linhas deve fazer você começar a fazer perguntas.

B. Classe grande 🔗 Uma classe contém muitos campos / métodos / linhas de código.

C. Obsessão primitiva 🔗

  • Uso de primitivas em vez de objetos pequenos para tarefas simples (como moeda, intervalos, seqüências especiais para números de telefone etc.)
  • Uso de constantes para codificar informações (como uma constante USER_ADMIN_ROLE = 1 para se referir a usuários com direitos de administrador.)
  • Uso de constantes de cadeia como nomes de campo para uso em matrizes de dados.

D. Lista longa de parâmetros 🔗 Mais de três ou quatro parâmetros para um método.

E. Agrupamentos de dados 🔗 Às vezes, partes diferentes do código contêm grupos idênticos de variáveis ​​(como parâmetros para conectar-se a um banco de dados). Esses grupos devem ser transformados em suas próprias classes.

2. Abusadores de orientação a objetos

Todos esses odores são aplicação incompleta ou incorreta dos princípios de programação orientada a objetos.

A. Alternar declarações 🔗 Você tem um operador de switch complexo ou uma sequência de instruções if .

B. Campo temporário 🔗 Os campos temporários obtêm seus valores (e, portanto, são necessários aos objetos) somente sob determinadas circunstâncias. Fora dessas circunstâncias, eles estão vazios.

C. Pedido recusado 🔗 Se uma subclasse usa apenas alguns dos métodos e propriedades herdados de seus pais, a hierarquia é desequilibrada. Os métodos desnecessários podem simplesmente não ser utilizados ou ser redefinidos e emitir exceções.

D. Classes alternativas com diferentes interfaces 🔗 Duas classes executam funções idênticas, mas têm nomes de métodos diferentes.

3. Preventores de mudanças

Esses cheiros significam que, se você precisar alterar algo em um local do seu código, também precisará fazer muitas alterações em outros locais. O desenvolvimento do programa se torna muito mais complicado e caro como resultado.

A. Mudança divergente 🔗 Você se vê tendo que alterar muitos métodos não relacionados ao fazer alterações em uma classe. Por exemplo, ao adicionar um novo tipo de produto, é necessário alterar os métodos para localizar, exibir e solicitar produtos.

B. Shotgun Surgery 🔗 Fazer qualquer modificação requer que você faça muitas pequenas alterações em várias classes diferentes.

C. Hierarquias de herança paralela 🔗 Sempre que você cria uma subclasse para uma classe, você precisa criar uma subclasse para outra classe.

4. Dispensáveis

Um dispensável é algo inútil e desnecessário cuja ausência tornaria o código mais limpo, mais eficiente e mais fácil de entender.

A. Comentários 🔗 Um método é preenchido com comentários explicativos.

B. Código duplicado 🔗 Dois fragmentos de código parecem quase idênticos.

C. Classe preguiçosa 🔗 Compreender e manter as aulas sempre custa tempo e dinheiro. Portanto, se uma turma não fizer o suficiente para atrair sua atenção, ela deverá ser excluída.

D. Classe de dados 🔗 Uma classe de dados se refere a uma classe que contém apenas campos e métodos brutos para acessá-los (getters e setters). Estes são simplesmente contêineres para dados usados ​​por outras classes. Essas classes não contêm nenhuma funcionalidade adicional e não podem operar independentemente nos dados que eles possuem.

E. Código Morto 🔗 Uma variável, parâmetro, campo, método ou classe não é mais usada (geralmente porque é obsoleta).

F. Generalidade especulativa 🔗 Há uma classe, método, campo ou parâmetro não utilizado.

5. Acopladores

Todos os cheiros deste grupo contribuem para o acoplamento excessivo entre as classes ou mostram o que acontece se o acoplamento for substituído por delegação excessiva.

A. Inveja do recurso 🔗 Um método acessa os dados de outro objeto mais do que seus próprios dados.

B. Intimidade inadequada 🔗 Uma classe usa os campos e métodos internos de outra classe.

C. Cadeias de Mensagens 🔗 No código, você vê uma série de chamadas semelhantes a $a->b()->c()->d()

D. Middle Man 🔗 Se uma classe executa apenas uma ação, delegando trabalho a outra classe, por que existe?

PARTE III

Técnicas de refatoração

1. Métodos de composição

Grande parte da refatoração é dedicada à composição correta dos métodos. Na maioria dos casos, métodos excessivamente longos são a raiz de todo mal. Os caprichos de código dentro desses métodos ocultam a lógica de execução e tornam o método extremamente difícil de entender — e ainda mais difícil de mudar.

As técnicas de refatoração neste grupo simplificam os métodos, removem a duplicação de código e abrem caminho para melhorias futuras.

A. Método de extração 🔗 Problema: você tem um fragmento de código que pode ser agrupado. Solução: mova esse código para um novo método (ou função) separado e substitua o código antigo por uma chamada ao método.

B. Método em linha 🔗 Problema: Quando um corpo de método é mais óbvio que o próprio método, use esta técnica. Solução: substitua as chamadas para o método pelo conteúdo do método e exclua o próprio método.

C. Extrair Variável 🔗 Problema: você tem uma expressão difícil de entender. Solução: Coloque o resultado da expressão ou de suas partes em variáveis ​​separadas que são auto-explicativas.

D. Temp Inline 🔗 Problema: você tem uma variável temporária à qual é atribuído o resultado de uma expressão simples e nada mais. Solução: Substitua as referências à variável pela própria expressão.

E. Substituir Temp por Consulta 🔗 Problema: Você coloca o resultado de uma expressão em uma variável local para uso posterior no seu código. Solução: Mova a expressão inteira para um método separado e retorne o resultado. Consulte o método em vez de usar uma variável. Incorpore o novo método em outros métodos, se necessário.

F. Dividir variável temporária 🔗 Problema: você tem uma variável local usada para armazenar vários valores intermediários dentro de um método (exceto para variáveis ​​de ciclo). Solução: use variáveis ​​diferentes para valores diferentes. Cada variável deve ser responsável por apenas uma coisa em particular.

G. Remover atribuições a parâmetros 🔗 Problema: algum valor é atribuído a um parâmetro dentro do corpo do método. Solução: use uma variável local em vez de um parâmetro.

H. Substituir método por objeto de método 🔗 Problema: Você tem um método longo no qual as variáveis ​​locais estão tão entrelaçadas que não é possível aplicar o Método de Extração. Solução: Transforme o método em uma classe separada para que as variáveis ​​locais se tornem campos da classe. Em seguida, você pode dividir o método em vários métodos dentro da mesma classe.

I. Algoritmo Substituto 🔗 Problema: Então você deseja substituir um algoritmo existente por um novo? Solução: Substitua o corpo do método que implementa o algoritmo por um novo algoritmo.

2. Movendo recursos entre objetos

Mesmo que você tenha distribuído a funcionalidade entre diferentes classes de uma maneira menos que perfeita, ainda há esperança.

Essas técnicas de refatoração mostram como mover com segurança a funcionalidade entre classes, criar novas classes e ocultar detalhes de implementação do acesso público.

A. Mover método 🔗 Problema: Um método é usado mais em outra classe do que em sua própria classe. Solução: crie um novo método na classe que mais utiliza o método e mova o código do método antigo para lá. Transforme o código do método original em uma referência ao novo método na outra classe ou remova-o completamente.

B. Mover campo 🔗 Problema: Um campo é usado mais em outra classe do que em sua própria classe. Solução: crie um campo em uma nova classe e redirecione todos os usuários do campo antigo para ele.

C. Extrair Classe 🔗 Problema: Quando uma turma faz o trabalho de duas, resulta um constrangimento. Solução: em vez disso, crie uma nova classe e coloque os campos e métodos responsáveis ​​pela funcionalidade relevante nela.

D. Classe em linha 🔗 Problema: Uma classe não faz quase nada e não é responsável por nada, e nenhuma responsabilidade adicional é planejada para ela. Solução: Mova todos os recursos da classe para outro.

E. Ocultar delegado 🔗 Problema: O cliente obtém o objeto B de um campo ou método do objeto À. Em seguida, o cliente chama um método do objeto B. Solução: Crie um novo método na classe A que delegue a chamada para o objeto B. Agora o cliente não conhece ou depende da classe B.

F. Como remover Middle Man 🔗 Problema: Uma classe possui muitos métodos que simplesmente delegam para outros objetos. Solução: exclua esses métodos e force o cliente a chamar os métodos finais diretamente.

G. Introduzir método estrangeiro 🔗 Problema: Uma classe de utilitário não contém o método necessário e você não pode adicionar o método à classe. Solução: adicione o método a uma classe cliente e passe um objeto da classe utilitária para ele como argumento.

H. Introduzir extensão local 🔗 Problema: Uma classe de utilitário não contém alguns métodos que você precisa. Mas você não pode adicionar esses métodos à classe. Solução: Crie uma nova classe contendo os métodos e torne-a filha ou invólucro da classe de utilitário.

3. Organização de dados

Essas técnicas de refatoração ajudam no tratamento de dados, substituindo os primitivos pela funcionalidade de classe avançada.

Outro resultado importante é o desembaraço das associações de classes, o que torna as classes mais portáteis e reutilizáveis.

A. Campo de auto-encapsulação 🔗 Problema: Você usa acesso direto a campos particulares dentro de uma classe. Solução: crie um getter e um setter para o campo e use somente eles para acessar o campo.

B. Substituir valor de dados por objeto 🔗 Problema: Uma classe (ou grupo de classes) contém um campo de dados. O campo tem seu próprio comportamento e dados associados. Solução: crie uma nova classe, coloque o campo antigo e seu comportamento na classe e armazene o objeto da classe na classe original.

C. Alterar valor para referência 🔗 Problema: Portanto, você tem muitas instâncias idênticas de uma única classe que precisam ser substituídas por um único objeto. Solução: Converta os objetos idênticos em um único objeto de referência.

D. Alterar referência para valor 🔗 Problema: você tem um objeto de referência muito pequeno e com pouca frequência alterado para justificar o gerenciamento de seu ciclo de vida. Solução: Transforme-o em um objeto de valor.

E. Substituir matriz por objeto 🔗 Problema: você tem uma matriz que contém vários tipos de dados. Solução: Substitua a matriz por um objeto que terá campos separados para cada elemento.

F. Duplicar dados observados 🔗 Problema: Os dados do domínio são armazenados nas classes responsáveis ​​pela GUI? Solução: convém separar os dados em classes separadas, garantindo a conexão e a sincronização entre a classe de domínio e a GUI.

G. Alterar associação unidirecional para bidirecional 🔗 Problema: você tem duas classes que precisam usar os recursos da outra, mas a associação entre elas é unidirecional. Solução: adicione a associação ausente à classe que precisa.

H. Alterar associação bidirecional para unidirecional 🔗 Problema: você tem uma associação bidirecional entre classes, mas uma das classes não usa os recursos da outra. Solução: Remova a associação não utilizada.

I. Substituir número mágico por constante simbólica 🔗 Problema: Seu código usa um número que tem um certo significado. Solução: substitua esse número por uma constante que tenha um nome legível por humanos, explicando o significado do número.

J. Encapsular campo 🔗 Problema: você tem um campo público. Solução: torne o campo privado e crie métodos de acesso para ele.

K. Coleção Encapsular 🔗 Problema: Uma classe contém um campo de coleção e um getter e setter simples para trabalhar com a coleção. Solução: torne o valor retornado pelo getter somente leitura e crie métodos para adicionar / excluir elementos da coleção.

L. Substituir código de tipo por classe 🔗 Problema: Uma classe possui um campo que contém código de tipo. Os valores desse tipo não são usados ​​nas condições do operador e não afetam o comportamento do programa. Solução: Crie uma nova classe e use seus objetos em vez dos valores do código de tipo.

M. Substituir código de tipo por subclasses 🔗 Problema: Você tem um tipo codificado que afeta diretamente o comportamento do programa (os valores desse campo acionam vários códigos em condicionais). Solução: Crie subclasses para cada valor do tipo codificado. Em seguida, extraia os comportamentos relevantes da classe original para essas subclasses. Substitua o código de fluxo de controle por polimorfismo.

N. Substituir código de tipo por estado / estratégia 🔗 Problema: você tem um tipo codificado que afeta o comportamento, mas não pode usar subclasses para se livrar dele. Solução: Substitua o código de tipo por um objeto de estado. Se for necessário substituir um valor do campo pelo código do tipo, outro objeto de estado é “conectado”.

O. Substituir subclasse por campos 🔗 Problema: Você tem subclasses que diferem apenas em seus métodos (retorno constante). Solução: Substitua os métodos pelos campos da classe pai e exclua as subclasses.

4. Simplificando expressões condicionais

Os condicionais tendem a se tornar cada vez mais complicados em sua lógica ao longo do tempo, e ainda existem mais técnicas para combater isso.

A. Decompor Condicional 🔗 Problema: Você tem uma condicional complexa ( if-then / else ou switch ). Solução: decomponha as partes complicadas do condicional em métodos separados: a condição, then e else .

B. Consolidar expressão condicional 🔗 Problema: você tem vários condicionais que levam ao mesmo resultado ou ação. Solução: consolide todos esses condicionais em uma única expressão.

C. Consolide fragmentos condicionais duplicados 🔗 Problema: Código idêntico pode ser encontrado em todas as ramificações de uma condicional. Solução: Mova o código para fora do condicional.

D. Remover sinalizador de controle 🔗 Problema: Você tem uma variável booleana que atua como um sinalizador de controle para várias expressões booleanas. Solução: em vez da variável, use break , continue e return .

E. Substituir condicional aninhado por cláusulas de guarda 🔗 Problema: você tem um grupo de condicionais aninhados e é difícil determinar o fluxo normal da execução do código. Solução: isole todas as verificações especiais e casos de borda em cláusulas separadas e coloque-as antes das verificações principais. Idealmente, você deve ter uma lista “plana” de condicionais, uma após a outra.

F. Substituir condicional por polimorfismo 🔗 Problema: Você tem um condicional que executa várias ações, dependendo do tipo ou das propriedades do objeto. Solução: Crie subclasses que correspondam às ramificações da condicional. Neles, crie um método compartilhado e mova o código da ramificação correspondente da condicional para ele. Em seguida, substitua o condicional pela chamada de método relevante. O resultado é que a implementação adequada será alcançada via polimorfismo, dependendo da classe de objeto.

G. Introduzir objeto nulo 🔗 Problema: Como alguns métodos retornam null vez de objetos reais, você tem muitas verificações quanto a null no seu código. Solução: em vez de null , retorne um objeto nulo que exibe o comportamento padrão.

H. Introduzir asserção 🔗 Problema: Para que uma parte do código funcione corretamente, certas condições ou valores devem ser verdadeiros. Solução: Substitua essas suposições por verificações de afirmação específicas.

5. Simplificando chamadas de método

Os condicionais tendem a se tornar cada vez mais complicados em sua lógica ao longo do tempo, e ainda existem mais técnicas para combater isso.

A. Decompor Condicional 🔗 Problema: Você tem uma condicional complexa ( if-then / else ou switch ). Solução: decomponha as partes complicadas do condicional em métodos separados: a condição, then e else .

B. Consolidar expressão condicional 🔗 Problema: você tem vários condicionais que levam ao mesmo resultado ou ação. Solução: consolide todos esses condicionais em uma única expressão.

C. Consolide fragmentos condicionais duplicados 🔗 Problema: Código idêntico pode ser encontrado em todas as ramificações de uma condicional. Solução: Mova o código para fora do condicional.

D. Remover sinalizador de controle 🔗 Problema: Você tem uma variável booleana que atua como um sinalizador de controle para várias expressões booleanas. Solução: em vez da variável, use break , continue e return .

E. Substituir condicional aninhado por cláusulas de guarda 🔗 Problema: você tem um grupo de condicionais aninhados e é difícil determinar o fluxo normal da execução do código. Solução: isole todas as verificações especiais e casos de borda em cláusulas separadas e coloque-as antes das verificações principais. Idealmente, você deve ter uma lista “plana” de condicionais, uma após a outra.

F. Substituir condicional por polimorfismo 🔗 Problema: Você tem um condicional que executa várias ações, dependendo do tipo ou das propriedades do objeto. Solução: Crie subclasses que correspondam às ramificações da condicional. Neles, crie um método compartilhado e mova o código da ramificação correspondente da condicional para ele. Em seguida, substitua o condicional pela chamada de método relevante. O resultado é que a implementação adequada será alcançada via polimorfismo, dependendo da classe de objeto.

G. Introduzir objeto nulo 🔗 Problema: Como alguns métodos retornam null vez de objetos reais, você tem muitas verificações quanto a null no seu código. Solução: em vez de null , retorne um objeto nulo que exibe o comportamento padrão.

H. Introduzir asserção 🔗 Problema: Para que uma parte do código funcione corretamente, certas condições ou valores devem ser verdadeiros. Solução: Substitua essas suposições por verificações de afirmação específicas.

6. Lidar com a generalização

A abstração possui seu próprio grupo de técnicas de refatoração, associadas principalmente à movimentação de funcionalidades na hierarquia de herança de classes, criação de novas classes e interfaces e substituição de herança por delegação e vice-versa.

A. Pull Up Field 🔗 Problema: Duas classes têm o mesmo campo. Solução: remova o campo das subclasses e mova-o para a superclasse.

B. Método Pull Up 🔗 Problema: Suas subclasses têm métodos que executam trabalhos semelhantes. Solução: torne os métodos idênticos e mova-os para a superclasse relevante.

C. Puxar para cima o corpo do construtor 🔗 Problema: Suas subclasses têm construtores com código quase sempre idêntico. Solução: Crie um construtor de superclasse e mova o código que é o mesmo nas subclasses para ele. Chame o construtor da superclasse nos construtores da subclasse.

D. Método Push Down 🔗 Problema: O comportamento é implementado em uma superclasse usada por apenas uma (ou algumas) subclasses? Solução: mova esse comportamento para as subclasses.

E. Push Down Field 🔗 Problema: Um campo é usado apenas em algumas subclasses? Solução: Mova o campo para essas subclasses.

F. Extrair subclasse 🔗 Problema: Uma classe possui recursos que são usados ​​apenas em certos casos. Solução: Crie uma subclasse e use-a nesses casos.

G. Extrair Superclasse 🔗 Problema: Você tem duas classes com campos e métodos comuns. Solução: crie uma superclasse compartilhada para eles e mova todos os campos e métodos idênticos para ela.

H. Extrair interface 🔗 Problema: Vários clientes estão usando a mesma parte de uma interface de classe. Outro caso: parte da interface em duas classes é a mesma. Solução: Mova essa parte idêntica para sua própria interface.

I. Recolher Hierarquia 🔗 Problema: Você tem uma hierarquia de classes na qual uma subclasse é praticamente igual à sua superclasse. Solução: Mesclar a subclasse e a superclasse.

J. Método de modelo de formulário 🔗 Problema: Suas subclasses implementam algoritmos que contêm etapas semelhantes na mesma ordem. Solução: Mova a estrutura do algoritmo e etapas idênticas para uma superclasse e deixe a implementação das diferentes etapas nas subclasses.

K. Substituir herança por delegação 🔗 Problema: você tem uma subclasse que usa apenas uma parte dos métodos de sua superclasse (ou não é possível herdar dados da superclasse). Solução: crie um campo e coloque um objeto de superclasse, delegue métodos para o objeto de superclasse e livre-se da herança.

L. Substituir delegação por herança 🔗 Problema: Uma classe contém muitos métodos simples que delegam a todos os métodos de outra classe. Solução: torne a classe um herdador delegado, o que torna os métodos de delegação desnecessários.

Se você chegou até aqui. Parabéns!!!

Att,

Philipe Cairon M.

--

--

Mago Minimalista
Studio Oceano

Designer e Desenvolvedor Web. Sou aspirante por novas tecnologias, sempre em busca de ferramentas para incrementar o trabalho ou maximizar a produtividade.