Refactoring.
A controlled technique for improving the design of existing code. Browse by group, see the code smells these techniques treat, the test smells in your test suite, or the smells of AI-generated code.
Problema: Um método não tem dados suficientes para realizar certas ações. Solução: Crie um novo parâmetro para passar os dados necessários.
Problema: Um método não é usado por outras classes ou é usado apenas dentro de sua própria hierarquia de classes. Solução: Torne o método privado ou protegido.
Problema: Seus métodos contêm um grupo de parâmetros que se repete. Solução: Substitua esses parâmetros por um objeto.
Problema: Múltiplos métodos realizam ações semelhantes que diferem apenas em seus valores internos, números ou operações. Solução: Combine esses métodos usando um parâmetro que passará o valor especial necessário.
Problema: Você obtém vários valores de um objeto e depois os passa como parâmetros para um método. Solução: Em vez disso, tente passar o objeto inteiro.
Problema: Um parâmetro não é usado no corpo de um método. Solução: Remova o parâmetro não utilizado.
Problema: O valor de um campo deve ser definido apenas no momento de sua criação e não deve mudar em nenhum momento depois disso. Solução: Portanto, remova os métodos que definem o valor do campo.
Problema: O nome de um método não explica o que o método faz. Solução: Renomeie o método.
Problema: você tem um construtor complexo que faz algo mais do que apenas atribuir valores de parâmetros a campos do objeto. Solução: crie um método de fábrica e use-o para substituir as chamadas ao construtor.
Problema: Um método retorna um valor especial que indica um erro? Solução: Em vez disso, lance uma exceção.
Problema: Você lança uma exceção em um lugar onde um teste simples faria o trabalho? Solução: Substitua a exceção por um teste de condição.
Problema: Um método é dividido em partes, cada uma das quais é executada dependendo do valor de um parâmetro. Solução: Extraia as partes individuais do método para seus próprios métodos e chame-os em vez do método original.
Problema: chamar um método de consulta e passar seus resultados como parâmetros de outro método, quando esse método poderia chamar a consulta diretamente. Solução: em vez de passar o valor por meio de um parâmetro, tente colocar a chamada de consulta dentro do corpo do método.
Problema: Você tem um método que retorna um valor mas também altera algo dentro de um objeto? Solução: Divida o método em dois métodos separados. Como você esperaria, um deles deve retornar o valor e o outro modifica o objeto.
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.
Problema: Você tem um objeto de referência pequeno demais e alterado com pouca frequência para justificar o gerenciamento de seu ciclo de vida. Solução: Transforme-o em um objeto de valor.
Problema: Você tem duas classes que precisam, cada uma, usar os recursos da outra, mas a associação entre elas é apenas unidirecional. Solução: Adicione a associação que falta à classe que precisa dela.
Problema: Você tem muitas instâncias idênticas de uma mesma classe que precisa substituir por um único objeto. Solução: Converta os objetos idênticos em um único objeto de referência.
Problema: Os dados de domínio estão armazenados em classes responsáveis pela GUI? Solução: Então é uma boa ideia separar os dados em classes próprias, garantindo a conexão e a sincronização entre a classe de domínio e a GUI.
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/remover elementos da coleção.
Problema: Você tem um campo público. Solução: Torne o campo privado e crie métodos de acesso para ele.
Problema: Você tem um array que contém vários tipos de dados. Solução: Substitua o array por um objeto que terá campos separados para cada elemento.
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 dessa classe na classe original.
Problema: seu código usa um número que tem um certo significado. Solução: substitua esse número por uma constante com um nome legível por humanos que explique o significado do número.
Problema: Você tem subclasses que diferem apenas em seus métodos (que retornam constantes). Solução: Substitua os métodos por campos na classe pai e exclua as subclasses.
Problema: Uma classe tem um campo que contém um código de tipo. Os valores desse tipo não são usados em condições de operadores e não afetam o comportamento do programa. Solução: Crie uma nova classe e use seus objetos no lugar dos valores do código de tipo.
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 o valor de um campo por código de tipo, outro objeto de estado é “plugado”.
Problema: Você tem um tipo codificado que afeta diretamente o comportamento do programa (os valores desse campo disparam diversos trechos de código 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 controle de fluxo por polimorfismo.
Problema: Você usa acesso direto a campos privados dentro de uma classe. Solução: Crie um getter e um setter para o campo e use apenas eles para acessar o campo.
Problema: Você tem uma hierarquia de classes na qual uma subclasse é praticamente igual à sua superclasse. Solução: Mescle a subclasse e a superclasse.
Problema: Vários clientes estão usando a mesma parte da interface de uma classe. Outro caso: parte da interface em duas classes é idêntica. Solução: Mova essa porção idêntica para sua própria interface.
Problema: uma classe tem funcionalidades que são usadas apenas em certos casos. Solução: crie uma subclasse e use-a nesses casos.
Problema: Você tem duas classes com campos e métodos em comum. Solução: Crie uma superclasse compartilhada para elas e mova todos os campos e métodos idênticos para ela.
Problema: Suas subclasses implementam algoritmos que contêm etapas semelhantes na mesma ordem. Solução: Mova a estrutura do algoritmo e as etapas idênticas para uma superclasse, e deixe a implementação das etapas diferentes nas subclasses.
Problema: suas subclasses têm construtores com código quase idêntico. Solução: crie um construtor na superclasse e mova para ele o código que é igual nas subclasses. Chame o construtor da superclasse nos construtores das subclasses.
Problema: Duas classes têm o mesmo campo. Solução: Remova o campo das subclasses e mova-o para a superclasse.
Problema: Suas subclasses têm métodos que realizam um trabalho semelhante. Solução: Torne os métodos idênticos e, em seguida, mova-os para a superclasse relevante.
Problema: Um campo é usado apenas em algumas subclasses? Solução: Mova o campo para essas subclasses.
Problema: Um comportamento implementado em uma superclasse é usado por apenas uma (ou algumas) subclasses? Solução: Mova esse comportamento para as subclasses.
Problema: Uma classe contém muitos métodos simples que delegam a todos os métodos de outra classe. Solução: Faça a classe herdar do delegado, o que torna os métodos delegadores desnecessários.
Problema: Você tem uma subclasse que usa apenas uma parte dos métodos de sua superclasse (ou não é possível herdar os dados da superclasse). Solução: Crie um campo e coloque nele um objeto da superclasse, delegue os métodos ao objeto da superclasse e elimine a herança.
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.
Problema: Código idêntico pode ser encontrado em todas as ramificações de um condicional. Solução: Mova o código para fora do condicional.
Problema: Você tem uma condicional complexa (if-then/else ou switch). Solução: Decomponha as partes complicadas da condicional em métodos separados: a condição, o then e o else.
Problema: para que um trecho de código funcione corretamente, certas condições ou valores precisam ser verdadeiros. Solução: substitua essas suposições por verificações de asserção específicas.
Problema: Como alguns métodos retornam null em vez de objetos reais, você tem muitas verificações de null no seu código. Solução: Em vez de null, retorne um objeto nulo que apresenta o comportamento padrão.
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.
Problema: Você tem um condicional que executa várias ações dependendo do tipo ou das propriedades de um objeto. Solução: Crie subclasses correspondentes aos ramos do condicional. Nelas, crie um método compartilhado e mova para ele o código do ramo correspondente do condicional. Em seguida, substitua o condicional pela chamada do método relevante. O resultado é que a implementação adequada será obtida por meio de polimorfismo, dependendo da classe do objeto.
Problema: Você tem um grupo de condicionais aninhadas e é difícil determinar o fluxo normal de 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.
Problema: Quando uma classe faz o trabalho de duas, surge um desconforto. Solução: Em vez disso, crie uma nova classe e coloque nela os campos e métodos responsáveis pela funcionalidade relevante.
Problema: O cliente obtém o objeto B a partir de um campo ou método do objeto A. Em seguida, o cliente chama um método do objeto B. Solução: Crie um novo método na classe A que delega a chamada ao objeto B. Agora o cliente não conhece a classe B nem depende dela.
Problema: Uma classe quase não faz nada e não é responsável por nada, e nenhuma responsabilidade adicional está planejada para ela. Solução: Mova todas as funcionalidades da classe para outra.
Problema: Uma classe utilitária não contém o método de que você precisa e você não pode adicionar o método à classe. Solução: Adicione o método a uma classe cliente e passe a ela um objeto da classe utilitária como argumento.
Problema: uma classe utilitária não contém alguns métodos de 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 wrapper da classe utilitária.
Problema: Um campo é usado mais em outra classe do que na sua própria classe. Solução: Crie um campo em uma nova classe e redirecione todos os usuários do campo antigo para ele.
Problema: um método é usado mais em outra classe do que na sua própria classe. Solução: crie um novo método na classe que mais usa o método e, em seguida, 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 então remova-o por completo.
Problema: Uma classe tem métodos demais que simplesmente delegam para outros objetos. Solução: Exclua esses métodos e force o cliente a chamar os métodos finais diretamente.
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.
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 sejam autoexplicativas.
Problema: Quando o corpo de um método é mais óbvio que o próprio método, use esta técnica. Solução: Substitua as chamadas ao método pelo conteúdo do método e exclua o próprio método.
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.
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.
Problema: Você tem um método longo cujas variáveis locais estão tão entrelaçadas que não é possível aplicar Extrair Método. Solução: Transforme o método em uma classe separada para que as variáveis locais se tornem campos da classe. Então você pode dividir o método em vários métodos dentro da mesma classe.
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 dele. Consulte o método em vez de usar uma variável. Incorpore o novo método em outros métodos, se necessário.
Problema: você tem uma variável local usada para armazenar diversos valores intermediários dentro de um método (exceto variáveis de laço). Solução: use variáveis diferentes para valores diferentes. Cada variável deve ser responsável por apenas uma coisa em particular.
Problema: Então você quer substituir um algoritmo existente por um novo? Solução: Substitua o corpo do método que implementa o algoritmo por um novo algoritmo.