Cómo crear clases factoría sin usar if-else

Escrito por el , actualizado el .
java planeta-codigo programacion
Enlace permanente Comentarios

Java

En el artículo cómo crear clases factoría sin usar if-else se comentan varias formas para conseguirlo. Las soluciones que se proponen son usar:

  • Reflection: sin embargo esta solución obliga a que el cliente de la factoría conozca el nombre completo de la clase a crear incluyendo el paquete en el que está y hace que la factoría no abstraiga al cliente de conocerlo que puede ser uno de sus objetivos. Además el parámetro es un String con lo que en los refactors el compilador no nos ayudará, el compilador es una de mis 10 razones para seguir usando Java.
  • Map: en esta solución se asocia una clave (en String) con la clase que devuelve la factoría. Igualmente usar un String como clave es algo a evitar ya que es propenso a errores al no tener ayuda del compilador en los valores de los Strings si estas cambian.
  • Enum: en esta solución para eliminar los if-else se aprovecha de la propiedad del polimorfismo de los lenguajes orientados a objetos. El tipo Enum usado tiene un método que es implementado en cada uno de los tipos concretos de enum, en función de que utilice se crea la instancia adecuada del objeto.

Hay que notar otra diferencia entre la soluciones con if-else, Reflection y Enum y por otra parte la solución con Map y es que en el ejemplo las tres primeras crean una nueva instancia del validador cada vez que se llama a newInstance mientras que en la solución Map solo devuelve la instancia puesta en el mapa.

La solución del Enum el código resultante es bastante verboso y menos legible que las otras soluciones aún usando polimorfismo (en mi humilde opinión), por otra parte crear una nueva instancia de validador cada vez que se invoca a newInstance en la factoría puede que no sea lo que queramos (o quizá sí). Por esto voy a plantear una nueva solución que es usando un Enum como clave de un Map, que es una variante de la solución comentada en el artículo con Map. Es código de la nueva solución es el siguiente:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package io.github.picodotdev.blogbitix.java;

import java.util.EnumMap;
import java.util.Map;

public class ValidatorFactory {

    public enum ValidatorType {
        INT, LOOKUP, DATE, STRING_PATTERN
    }

    private static Map<ValidatorType, Validator> validators;

    static {
        validators = new EnumMap<>(ValidatorType.class);
        validators.put(ValidatorType.INT, new IntValidator());
        validators.put(ValidatorType.LOOKUP, new LookupValueValidator());
        validators.put(ValidatorType.DATE, new DateValidator());
        validators.put(ValidatorType.STRING_PATTERN, new StringPatternValidator());
    }

    public static Validator newInstance(ValidatorType type) {
        return validators.get(type);
    }
}
ValidatorFactory.java

Si necesitásemos que la factoría devolviese una nueva instancia de Validator en cada llamada a newInstance (por ejemplo, porque no es thread-safe) podemos poner en el mapa una instancia de Supplier haciendo uso de las funciones lambda incluidas como una de las nuevas características incorporadas en Java 8.

Cómo se comenta en los recomendables libros Refactoring: Improving the Design of Existing Code y Effective Java los if-else o switches son algo a evitar ya que se prefiere la pauta «abierto a extensión, cerrado a modificación», si necesitamos modificar código existente puede que introduzcamos algún error o se nos olvide modificar algún punto del código, por ello se prefiere el polimorfismo siendo la solución del Enum la más cercana a este principio o alguna de las otras soluciones. En el libro Effective Java además se comentan ideas interesantes y ventajas sobre por que usar factorías (en ciertas situaciones) en vez de la palabra clave reservada new. Sin embargo, hay que saber cuando aplicar cierto patrón ya que son soluciones en algún sentido mejor pero que añaden algo de complejidad, nos tocará en función de las modificaciones que preveamos que pueda tener el código, de las necesidades o experiencia saber cual aplicar.


Comparte el artículo: