Reemplazar condicional con polimorfismo.
Tienes un condicional que ejecuta diversas acciones en función del tipo o las propiedades de un objeto.
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.
##Example
class Bird {
// ...
double getSpeed() {
switch (type) {
case EUROPEAN:
return getBaseSpeed();
case AFRICAN:
return getBaseSpeed() - getLoadFactor() * numberOfCoconuts;
case NORWEGIAN_BLUE:
return (isNailed) ? 0 : getBaseSpeed(voltage);
}
throw new RuntimeException("Should be unreachable");
}
}abstract class Bird {
// ...
abstract double getSpeed();
}
class European extends Bird {
double getSpeed() {
return getBaseSpeed();
}
}
class African extends Bird {
double getSpeed() {
return getBaseSpeed() - getLoadFactor() * numberOfCoconuts;
}
}
class NorwegianBlue extends Bird {
double getSpeed() {
return (isNailed) ? 0 : getBaseSpeed(voltage);
}
}
// En algún lugar del código cliente
speed = bird.getSpeed();##Why Refactor
Esta técnica de refactorización puede ayudar si tu código contiene operadores que ejecutan diversas tareas que varían en función de:
-
La clase del objeto o la interfaz que implementa
-
El valor de un campo de un objeto
-
El resultado de llamar a uno de los métodos de un objeto
Si aparece una nueva propiedad o tipo de objeto, tendrás que buscar y añadir código en todos los condicionales similares. Por tanto, el beneficio de esta técnica se multiplica si hay múltiples condicionales repartidos por todos los métodos de un objeto.
##Benefits
-
Esta técnica respeta el principio Tell-Don’t-Ask (di, no preguntes): en lugar de preguntar a un objeto por su estado y luego ejecutar acciones en función de ello, es mucho más fácil simplemente decirle al objeto qué tiene que hacer y dejar que decida por sí mismo cómo hacerlo.
-
Elimina código duplicado. Te deshaces de muchos condicionales casi idénticos.
-
Si necesitas añadir una nueva variante de ejecución, lo único que tienes que hacer es añadir una nueva subclase sin tocar el código existente (principio abierto/cerrado).
##How to Refactor
Preparación para la refactorización
Para esta técnica de refactorización deberías tener lista una jerarquía de clases que contenga los comportamientos alternativos. Si no tienes una jerarquía así, créala. Otras técnicas te ayudarán a conseguirlo:
-
Reemplazar código de tipo con subclases. Se crearán subclases para todos los valores de una determinada propiedad del objeto. Este enfoque es sencillo, pero menos flexible, ya que no puedes crear subclases para las demás propiedades del objeto.
-
Reemplazar código de tipo con estado/estrategia. Se dedicará una clase a una determinada propiedad del objeto y se crearán subclases a partir de ella para cada valor de la propiedad. La clase actual contendrá referencias a los objetos de este tipo y les delegará la ejecución.
Los pasos siguientes asumen que ya has creado la jerarquía.
Pasos de la refactorización
-
Si el condicional está en un método que también ejecuta otras acciones, aplica Extraer método.
-
Para cada subclase de la jerarquía, redefine el método que contiene el condicional y copia en esa ubicación el código de la rama correspondiente del condicional.
-
Elimina esta rama del condicional.
-
Repite el reemplazo hasta que el condicional quede vacío. Después, elimina el condicional y declara el método como abstracto.