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: Un método no tiene suficientes datos para realizar ciertas acciones. Solución: Crea un nuevo parámetro para pasar los datos necesarios.
Problema: Un método no es utilizado por otras clases o se utiliza únicamente dentro de su propia jerarquía de clases. Solución: Haz el método privado o protegido.
Problema: Tus métodos contienen un grupo de parámetros que se repite. Solución: Sustituye estos parámetros por un objeto.
Problema: Varios métodos realizan acciones similares que solo se diferencian en sus valores internos, números u operaciones. Solución: Combina estos métodos utilizando un parámetro que pase el valor especial necesario.
Problema: Obtienes varios valores de un objeto y después los pasas como parámetros a un método. Solución: En lugar de eso, intenta pasar el objeto completo.
Problema: Un parámetro no se utiliza en el cuerpo de un método. Solución: Elimina el parámetro no utilizado.
Problema: El valor de un campo debería establecerse solo cuando se crea, y no cambiar en ningún momento posterior. Solución: Por lo tanto, elimina los métodos que establecen el valor del campo.
Problema: El nombre de un método no explica lo que hace. Solución: Renombra el método.
Problema: tienes un constructor complejo que hace algo más que limitarse a asignar los valores de los parámetros a los campos del objeto. Solución: crea un método de fábrica y úsalo para reemplazar las llamadas al constructor.
Problema: ¿Un método devuelve un valor especial que indica un error? Solución: Lanza una excepción en su lugar.
Problema: ¿Lanzas una excepción en un lugar donde una simple comprobación haría el trabajo? Solución: Reemplaza la excepción con una comprobación de condición.
Problema: Un método está dividido en partes, cada una de las cuales se ejecuta dependiendo del valor de un parámetro. Solución: Extrae las partes individuales del método en sus propios métodos y llámalos en lugar del método original.
Problema: Llamas a un método de consulta y pasas sus resultados como parámetros de otro método, cuando ese método podría llamar a la consulta directamente. Solución: En lugar de pasar el valor a través de un parámetro, intenta colocar una llamada a la consulta dentro del cuerpo del método.
Problema: ¿Tienes un método que devuelve un valor pero también cambia algo dentro de un objeto? Solución: Divide el método en dos métodos independientes. Como es de esperar, uno de ellos debe devolver el valor y el otro modifica el objeto.
Problema: Tienes una asociación bidireccional entre clases, pero una de las clases no usa las características de la otra. Solución: Elimina la asociación no utilizada.
Problema: Tienes un objeto de referencia demasiado pequeño y que cambia con poca frecuencia como para justificar la gestión de su ciclo de vida. Solución: Conviértelo en un objeto de valor.
Problema: Tienes dos clases que necesitan usar cada una las características de la otra, pero la asociación entre ellas es únicamente unidireccional. Solución: Añade la asociación que falta a la clase que la necesita.
Problema: Tienes muchas instancias idénticas de una misma clase que necesitas reemplazar con un único objeto. Solución: Convierte los objetos idénticos en un único objeto de referencia.
Problema: ¿Se almacenan datos de dominio en clases responsables de la GUI? Solución: En ese caso, conviene separar los datos en clases independientes, asegurando la conexión y sincronización entre la clase de dominio y la GUI.
Problema: Una clase contiene un campo de colección y un getter y un setter simples para trabajar con la colección. Solución: Haz que el valor devuelto por el getter sea de solo lectura y crea métodos para añadir o eliminar elementos de la colección.
Problema: Tienes un campo público. Solución: Haz que el campo sea privado y crea métodos de acceso para él.
Problema: Tienes un array que contiene varios tipos de datos. Solución: Reemplaza el array con un objeto que tendrá campos separados para cada elemento.
Problema: Una clase (o grupo de clases) contiene un campo de datos. El campo tiene su propio comportamiento y datos asociados. Solución: Crea una nueva clase, coloca en ella el antiguo campo y su comportamiento, y almacena el objeto de la clase dentro de la clase original.
Problema: Tu código usa un número que tiene cierto significado. Solución: Reemplaza ese número por una constante con un nombre legible que explique el significado del número.
Problema: Tienes subclases que se diferencian únicamente en sus métodos (que devuelven constantes). Solución: Reemplaza los métodos con campos en la clase padre y elimina las subclases.
Problema: Una clase tiene un campo que contiene un código de tipo. Los valores de este tipo no se usan en condiciones de operadores y no afectan al comportamiento del programa. Solución: Crea una nueva clase y usa sus objetos en lugar de los valores del código de tipo.
Problema: tienes un tipo codificado que afecta al comportamiento pero no puedes usar subclases para deshacerte de él. Solución: reemplaza el código de tipo por un objeto de estado. Si es necesario reemplazar el valor de un campo con código de tipo, se «conecta» otro objeto de estado.
Problema: tienes un tipo codificado que afecta directamente al comportamiento del programa (los valores de este campo disparan distinto código en condicionales). Solución: crea subclases para cada valor del tipo codificado. Luego extrae los comportamientos relevantes de la clase original a estas subclases. Reemplaza el código de control de flujo con polimorfismo.
Problema: Usas acceso directo a campos privados dentro de una clase. Solución: Crea un getter y un setter para el campo, y úsalos únicamente a ellos para acceder al campo.
Problema: Tienes una jerarquía de clases en la que una subclase es prácticamente igual que su superclase. Solución: Fusiona la subclase y la superclase.
Problema: Varios clientes utilizan la misma parte de la interfaz de una clase. Otro caso: parte de la interfaz de dos clases es idéntica. Solución: Mueve esa porción idéntica a su propia interfaz.
Problema: Una clase tiene características que solo se usan en determinados casos. Solución: Crea una subclase y úsala en esos casos.
Problema: Tienes dos clases con campos y métodos comunes. Solución: Crea una superclase compartida para ellas y mueve a ella todos los campos y métodos idénticos.
Problema: Tus subclases implementan algoritmos que contienen pasos similares en el mismo orden. Solución: Mueve la estructura del algoritmo y los pasos idénticos a una superclase, y deja la implementación de los pasos diferentes en las subclases.
Problema: tus subclases tienen constructores con código que es casi idéntico. Solución: crea un constructor en la superclase y traslada a él el código que es igual en las subclases. Llama al constructor de la superclase desde los constructores de las subclases.
Problema: Dos clases tienen el mismo campo. Solución: Elimina el campo de las subclases y muévelo a la superclase.
Problema: Tus subclases tienen métodos que realizan un trabajo similar. Solución: Haz que los métodos sean idénticos y luego muévelos a la superclase correspondiente.
Problema: ¿Se usa un campo solo en unas pocas subclases? Solución: Mueve el campo a esas subclases.
Problema: ¿El comportamiento implementado en una superclase es utilizado por una sola subclase (o por unas pocas)? Solución: Mueve este comportamiento a las subclases.
Problema: Una clase contiene muchos métodos sencillos que delegan en todos los métodos de otra clase. Solución: Haz que la clase sea heredera del delegado, lo que vuelve innecesarios los métodos delegantes.
Problema: Tienes una subclase que usa solo una parte de los métodos de su superclase (o no es posible heredar los datos de la superclase). Solución: Crea un campo y coloca en él un objeto de la superclase, delega los métodos en el objeto de la superclase y elimina la herencia.
Problema: Tienes varios condicionales que conducen al mismo resultado o acción. Solución: Consolida todos esos condicionales en una sola expresión.
Problema: Se encuentra código idéntico en todas las ramas de un condicional. Solución: Mueve el código fuera del condicional.
Problema: Tienes un condicional complejo (if-then/else o switch). Solución: Descompón las partes complicadas del condicional en métodos separados: la condición, el then y el else.
Problema: para que una porción de código funcione correctamente, ciertas condiciones o valores deben ser verdaderos. Solución: sustituye estas suposiciones por comprobaciones de aserción concretas.
Problema: Como algunos métodos devuelven null en lugar de objetos reales, tienes muchas comprobaciones de null en tu código. Solución: En lugar de null, devuelve un objeto nulo que muestre el comportamiento por defecto.
Problema: Tienes una variable booleana que actúa como bandera de control para múltiples expresiones booleanas. Solución: En lugar de la variable, utiliza break, continue y return.
Problema: Tienes un condicional que ejecuta diversas acciones en función del tipo o las propiedades de un objeto. Solución: Crea subclases que se correspondan con las ramas del condicional. En ellas, crea un método compartido y traslada a él el código de la rama correspondiente del condicional. Después, reemplaza el condicional por la llamada al método pertinente. El resultado es que se alcanzará la implementación adecuada mediante polimorfismo en función de la clase del objeto.
Problema: Tienes un grupo de condicionales anidados y es difícil determinar el flujo normal de ejecución del código. Solución: Aísla todas las comprobaciones especiales y los casos límite en cláusulas separadas y colócalas antes de las comprobaciones principales. Lo ideal es tener una lista «plana» de condicionales, uno tras otro.
Problema: Cuando una clase hace el trabajo de dos, surge la incomodidad. Solución: En su lugar, crea una clase nueva y coloca en ella los campos y métodos responsables de la funcionalidad correspondiente.
Problema: El cliente obtiene el objeto B a partir de un campo o método del objeto A. Después, el cliente llama a un método del objeto B. Solución: Crea un nuevo método en la clase A que delegue la llamada al objeto B. Ahora el cliente no conoce la clase B ni depende de ella.
Problema: Una clase casi no hace nada y no es responsable de nada, y no se planean responsabilidades adicionales para ella. Solución: Mueve todas las características de la clase a otra.
Problema: una clase de utilidad no contiene el método que necesitas y no puedes añadirlo a la clase. Solución: añade el método a una clase cliente y pásale como argumento un objeto de la clase de utilidad.
Problema: una clase de utilidad no contiene algunos métodos que necesitas, pero no puedes añadir esos métodos a la clase. Solución: crea una clase nueva que contenga los métodos y conviértela en hija o en envoltorio (wrapper) de la clase de utilidad.
Problema: Un campo se utiliza más en otra clase que en la suya propia. Solución: Crea un campo en una nueva clase y redirige hacia él a todos los usuarios del campo antiguo.
Problema: un método se usa más en otra clase que en la suya propia. Solución: crea un método nuevo en la clase que más lo usa y traslada allí el código del método antiguo. Convierte el código del método original en una referencia al nuevo método de la otra clase, o bien elimínalo por completo.
Problema: Una clase tiene demasiados métodos que simplemente delegan en otros objetos. Solución: Elimina estos métodos y obliga al cliente a llamar directamente a los métodos finales.
Problema: tienes un fragmento de código que se puede agrupar. Solución: traslada este código a un nuevo método (o función) independiente y sustituye el código antiguo por una llamada al método.
Problema: Tienes una expresión difícil de entender. Solución: Coloca el resultado de la expresión o de sus partes en variables separadas que se expliquen por sí mismas.
Problema: Cuando el cuerpo de un método es más evidente que el propio método, usa esta técnica. Solución: Sustituye las llamadas al método por el contenido del método y elimina el propio método.
Problema: Tienes una variable temporal a la que se asigna el resultado de una expresión simple y nada más. Solución: Sustituye las referencias a la variable por la propia expresión.
Problema: Se asigna algún valor a un parámetro dentro del cuerpo del método. Solución: Usa una variable local en lugar de un parámetro.
Problema: Tienes un método largo en el que las variables locales están tan entrelazadas que no puedes aplicar Extraer método. Solución: Transforma el método en una clase separada de modo que las variables locales se conviertan en campos de la clase. Después podrás dividir el método en varios métodos dentro de la misma clase.
Problema: Colocas el resultado de una expresión en una variable local para su uso posterior en el código. Solución: Mueve toda la expresión a un método independiente y devuelve el resultado desde él. Consulta el método en lugar de usar una variable. Incorpora el nuevo método en otros métodos, si es necesario.
Problema: Tienes una variable local que se utiliza para almacenar varios valores intermedios dentro de un método (salvo las variables de los bucles). Solución: Usa variables distintas para valores distintos. Cada variable debe ser responsable de una sola cosa en concreto.
Problema: ¿Quieres reemplazar un algoritmo existente por uno nuevo? Solución: Reemplaza el cuerpo del método que implementa el algoritmo por un algoritmo nuevo.