Reemplazar código de tipo con subclases.
Tienes un tipo codificado que afecta directamente al comportamiento del programa (los valores de este campo disparan distinto código en condicionales).
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.
##Example
##Why Refactor
Esta técnica de refactorización es una variante más complicada de Reemplazar código de tipo con clase.
Como en el primer método de refactorización, tienes un conjunto de valores simples que constituyen todos los valores permitidos para un campo. Aunque estos valores a menudo se especifican como constantes y tienen nombres comprensibles, su uso hace que tu código sea muy propenso a errores, ya que en la práctica siguen siendo primitivos. Por ejemplo, tienes un método que acepta uno de estos valores en los parámetros. En cierto momento, en lugar de la constante USER_TYPE_ADMIN con el valor "ADMIN", el método recibe la misma cadena en minúsculas ("admin"), lo que provocará la ejecución de algo distinto de lo que el autor (tú) pretendía.
Aquí estamos tratando con código de control de flujo como los condicionales if, switch y ?:. En otras palabras, los campos con valores codificados (como $user->type === self::USER_TYPE_ADMIN) se usan dentro de las condiciones de estos operadores. Si usáramos aquí Reemplazar código de tipo con clase, lo mejor sería mover todas estas construcciones de control de flujo a una clase responsable del tipo de datos. En última instancia, esto crearía, por supuesto, una clase de tipo muy similar a la original, con los mismos problemas.
##Benefits
-
Elimina el código de control de flujo. En lugar de un
switchvoluminoso en la clase original, mueve el código a las subclases apropiadas. Esto mejora la adhesión al Principio de Responsabilidad Única y hace el programa más legible en general. -
Si necesitas añadir un nuevo valor para un tipo codificado, todo lo que tienes que hacer es añadir una nueva subclase sin tocar el código existente (cf. el Principio Abierto/Cerrado).
-
Al reemplazar el código de tipo con clases, allanamos el camino para la indicación de tipos (type hinting) de métodos y campos a nivel del lenguaje de programación. Esto no sería posible usando simples valores numéricos o de cadena contenidos en un tipo codificado.
##How to Refactor
-
Usa Autoencapsular campo para crear un getter para el campo que contiene el código de tipo.
-
Haz privado el constructor de la superclase. Crea un método de fábrica estático con los mismos parámetros que el constructor de la superclase. Debe contener el parámetro que tomará los valores iniciales del código de tipo. Dependiendo de este parámetro, el método de fábrica creará objetos de varias subclases. Para ello, en su código deberás crear un gran condicional pero, al menos, será el único cuando sea verdaderamente necesario; de lo contrario, se encargarán las subclases y el polimorfismo.
-
Crea una subclase única para cada valor del código de tipo. En ella, redefine el getter del código de tipo para que devuelva el valor correspondiente del código de tipo.
-
Elimina el campo con el código de tipo de la superclase. Haz su getter abstracto.
-
Ahora que tienes subclases, puedes empezar a mover los campos y métodos de la superclase a las subclases correspondientes (con ayuda de Bajar campo y Bajar método).
-
Cuando se haya movido todo lo posible, usa Reemplazar condicional con polimorfismo para deshacerte de las condiciones que usan el código de tipo de una vez por todas.