Professional Java EE Design Patterns

Portada de Java EE Design Patterns

La semana pasada acabé de leer Professional Java EE Design Patterns. Hace tiempo anoté para leer el clásico Real World Java EE Patterns Rethinking Best Practices ya que tenía pendiente leer un libro sobre Java EE pero preferí buscar un libro sobre una versión de Java más reciente.

Cortito y fácil de leer, no es un libro para aprender Java EE. No se explican al detalle los componentes de Java EE 7 por lo que es conveniente tener cierta base en el estándar o en algún otro framework como Spring.

Los autores tratan la intersección entre la API de Java EE y los patrones de diseño. Explican brevemente qué son (apoyándose en el libro de GoF y en el HFDP) y cómo se implementan con Java EE. Después de haber leído Head First Design PatternsClean code o Code Complete es una buena continuación para profundizar en patrones de diseño desde un punto de vista más práctico.

No obstante, lo que más estoy valorando de este libro es la tremenda experiencia que han plasmado los autores a través de dos vías:

– Comentando la evolución de Java EE desde su primera versión hasta la actualidad explicando cómo se ha visto afectada por diseños demasiados complejos y cómo han adoptado características de frameworks como Spring cuando esta implementación ha dado mejores resultados y se ha convertido en el estándar de facto.

– Resaltando las ventajas y desventajas de aplicar estos patrones y temas a tener en cuenta como la concurrencia o la complejidad añadida. Han conseguido aportar su gran experiencia en una componente práctica que complementa perfectamente la teoría de de patrones de diseño.

Como única pega, la filosofía convención sobre configuración también se aplica en los ejemplos de este libro y no siempre es trivial entender cómo funcionan algunos ejemplos con tan poco código. En algún que otro momento hay que recurrir al tutorial de Java EE para entender donde está el truco.

Para complementar, un buen repositorio con muchos ejemplos de uso de Java EE 7 muy interesantes https://github.com/javaee-samples/javaee7-samples

Cómo implementar el patrón factoría en Java EE 7

El patrón factoría es uno de los más sencillos de entender e implementar. El objetivo es separar la creación del uso de un objeto tanto por la responsabilidad de decidir qué implementación proporcionar como por la gestión de las dependencias.

Por ejemplo, se puede dejar que un recruiter sea el encargado de escoger al nuevo desarrollador que necesita la empresa. Podéis echarle un vistazo al código de ejemplo en https://gist.github.com/jonasurbano/f4f4b1b53e4dcec92be9

Java EE 7 permite una nueva forma de implementar el patrón factoría aunque, desde mi punto de vista, parece bastante compleja en comparación con la forma tradicional de implementarlo. Pero esta complejidad está justificada ya que evita acoplar la factoría a las implementaciones que puede generar.

En mi ejemplo Developer y DeveloperWithC1 implementan Person. El recruiter es PersonFactory que decidirá cuál es la implementación de Person que se necesita. Se decidirá que implementación se creará dependiendo del nivel de inglés con una anotación @EnglishLevel que contiene un enum Level { Intermediate, Advanced }.

Para que el contenedor de Java EE pueda determinar qué nivel tiene cada implementación de Person (Anotada con @EnglishLevel) un objeto EnglishLevelLiteral ha de heredar de AnnotationLiteral que será el criterio para que el recruiter busque entre todos sus desarrolladores que están contenidos en un objeto Instance<Person> (Instance hereda de Iterable).

Así, el método factoría getDeveloper(…) se escribe con dos líneas de código casi triviales. A destacar que no se ha escrito ni un “new” para implementaciones de Person y que el método no sabe (y esta es la gran ventaja) cuáles son las implementaciones de Person. De esto se encarga el contenedor de Java EE.

Anteriormente el método podría haberse escrito así:

/**
* Search among hundreds of resumes
*/
public Person getDeveloper(EnglishLevel.Level type) {
    Person person = null;

    switch (type) {
        case Advanced: person = new Developer();
        case Intermediate: person = new DeveloperWithC1();
    }

    return person;
}

Obligando a la factoría a conocer todas las implementaciones. Si ahora se necesita añadir como nivel Proficency habría que modificar tanto el enum como el método factoría. De la nueva manera que propone Java EE 7 sólo es necesario modificar el enum.

En conclusión, aunque hay que utilizar alguna que otra clase de más para implementar el patrón factoría, las ventajas de usar la última versión del contenedor de aplicaciones son varias consiguiendo un diseño muy claro y en línea con los principios de orientación a objetos.