Patrón de Diseño Factory

Patrón de diseño Factory Method

El patrón de diseño Factory Method nos permite la creación de un subtipo determinado por medio de una clase de Factoría, la cual oculta los detalles de creación del objeto.

El objeto real creados es enmascarado detrás de una interface común entre todos los objetos que pueden ser creado, con la finalidad de que estos pueden variar sin afectar la forma en que el cliente interactúa con ellos. 

Es normal que un Factory pueda crear varios subtipos de una determinada interface y que todos los objetos concretos fabricados hagan una tarea similar pero con detalles de implementación diferentes. 

La intención del Factory Method es tener una clase a la cual delegar la responsabilidad de la creación de los objetos, para que no sea el mismo programador el que decida que clase instanciará, si no que delegará esta responsabilidad al Factory confiando en que este le regresará la clase adecuada para trabajar.

Lo anterior puede resultado un poco absurdo, pues para que necesitaría el programador ayuda de una clase para crear un objeto, en su lugar puede hacer simplemente un new y listo, tiene la instancia creada, sin embargo, el patrón Factory method se utiliza para casos en los que no se sabe en tiempo de diseño que subtipo vamos a necesitar, y en su lugar, definimos eso en la base de datos, en un archivo de configuración, o simplemente por medio de alguna condición en tiempo de ejecución podemos determinar que clase se utilizará.


Estructura del patrón Factory Method

El siguiente diagrama muestra los componentes que conforman el patrón de diseño:

  • IProduct: Representa de forma abstracta el objeto que queremos crear, mediante esta interface se definen la estructura que tendrá el objeto creado.
  • ConcreteProduct: Representa una implementación concreta de la interface IProduct, la cual es creada a través del ConcreteFactory.
  • AbstractFactory: Este componente puede ser opcional, sin embargo, se recomienda la creación de un AbstractFactory que define el comportamiento por default de los ConcreteFactory.
  • Concrete Factory: Representa una fábrica concreta la cual es utilizada para la creación de los ConcreteProduct, esta clase hereda el comportamiento básico del AbstractFactory.



Secuencia de ejecución

La siguiente sección describe la secuencia de ejecución del patrón

El diagrama se interpreta de la siguiente manera:

  1. El cliente le solicita al ConcreteFactory la creación del ProductA .
  2. El ConcreteFactory localiza la implementación concreta de ProductA y crea una nueva instancia.
  3. El ConcreteFactory regresa el ConcreteProductA creado.
  4. El cliente le solicita al ConcreteFactory la creación del ProductB.
  5. El ConcreteFactory localiza la implementación concreta del ProductB y crea una nueva instancia.
  6. El ConcreteFactory regresa el ConcreteProductB creado.



Ejemplo práctico

Para comprender mejor como funciona el patrón Factory Method analizaremos un ejemplo prácticos con el cual podemos presentarnos alguno de nuestros proyectos, el cual corresponde a una aplicación que se puede conectar a más de una base de datos, sin embargo, la base de datos a utilizar no se sabrá de antemano, si no que por medio de la configuración es como podremos determinar que base de datos estaremos utilizando.

Como vemos, en este caso, no está clara la base de datos que vamos a utilizar, por lo tanto no podemos crear una aplicación que se conecta a una base de datos determinada, si no que tenemos que esperar hasta conocer la configuración para poder establecer la conexión. Una posible solución es crear una serie de IF…ELSE IF para crear la conexión al momento de leer la configuración, sin embargo, esto no es para nada recomendable, pues crearemos una aplicación difícil de mantener y que además revuelva la lógica para determinar la base de datos junto con la lógica propia del sistema.

En su lugar, lo recomendable es crear un Factory Method que nos cree un objeto que nos permita conectarnos a la base de datos, y que este objeto oculte los detalles de implementación, por otro lado, el Factory Method ocultara los detalles de implementación para leer la configuración y crear el objeto adecuado según la configuración, de esta forma, todos los detalles son ocultados al cliente y este solo se preocupa por implementar la lógica.

Antes de comenzar, puedes ver todo el código fuente en GitHub: https://github.com/oscarjb1/blog-patterns-factorymethod


Lo primero será definir la interface que implementarán las clases que se conectarán a la base de datos:


Esta interface solo define el método getConnection, la cual deberá regresar una conexión abierta a la base de datos.

El siguiente paso es crear las clases concretas que se conectarán a las bases de datos Oracle, MySQL y SQLServer:


Como acabamos de ver, estas clases tiene como única responsabilidad de crear la conexiones a las base de datos y registrar el driver JDBC correspondiente. Adicional, utilizan un archivo de configuración para recuperar los datos de conexión, el cual analizáramos más adelante.

Para recuperar la configuración se utiliza una clase de utilidad llamada ConfigLoader, la cual lee y carga en memoria el archivo dbconfig.properties:


El archivos de propiedades se ve de la siguiente manera:


Finalmente, tenemos la clase DBFactory, la cual se encarga de crear la instancia correcta de la interface IDBAdapter basado en el valor de la propiedad dbtype del archivo dbconfig.properties:


Como podemos apreciar, esta clase tiene una lógica para determina la clase que deberá de regresar, por su parte, el cliente no tiene por que saber cual es la implementación concreta que creará el Factory, lo que permitiría que en el futuro cambiáramos de implementación sin afectar al cliente.


Probando la solución

Finalmente, ejecutaremos una prueba para comprobar que todo funciona según lo explicado, para eso, creamos la clase Main, la cual se ve de la siguiente manera:


Al ejecutar este prueba tenemos como resultado la siguiente salida:


Como vemos, DBType indica que estamos utilizando la conexión a MySQL y al propiedad Is Open nos indica que la conexión se realizo correctamente. Si cambiamos la propiedad dbtype del archivo dbconfig.properties veremos como nos podemos conectar a las demás base de datos.

¿Te gustaría aprender más patrones como este? te invito a que veas mi nuevo libro “Introducción a los patrones de diseño”, donde explico los principales patrones de diseño desde un enfoque práctico y con ejemplos del mundo real. Olvídate de aprender con los ejemplos típicos de Internet, como crear una pizza, clase de animales que ladren o maullen, o figuras geométricas.



Conclusiones

Como hemos pido observar, implementar el patrón de diseño Factory Method es muy simple y otorga grandes ventajas que son fáciles de apreciar, como separar la lógica de creación de objetos en una clase de factoria o la facilidad de variar dinamicamnte la implementación del objeto fabricado sin afectar al cliente.


Artículos relacionados

Patrón de diseño Command El patrón de diseño Command es muy utilizado cuando se requiere hacer ejecuciones de operaciones sin conocer realmente lo que hacen, estas operaciones...
Métodos HTTP (REST) Los métodos HTTP definen la acción que se realizará sobre un determinado recurso. Los métodos HTTP, también suelen ser llamados HTTP Verbs. Aunque el ...
Java 9 – análisis de las novedades Java 9 trae importantes novedades, pero todo sobre sale el sistema de módulos, para conocer todo acerca de java 9, te invito a veas mi articulo "J...

Oscar Blancarte

Ideológico, Innovador y emprendedor, Padre, Tecnólogo y Autor, amante de la ciencia y la tecnología en todos sus colores y sabores. Arquitecto de software & Full Stack Developer con experiencia en la industria del desarrollo de software y la consultoría. Amante de la programación y el Ajedrez.

4 comentarios en “Patrón de Diseño Factory

  1. Saluton.
    Muy buen aporte, de gran utilidad para aprender la implementación de un patron Factory. En un principio yo tambien comence a utiliar los patrones Factory en conecciones a BD, pero en la actualidad he implementado entity framework, ya no he visto que se utilize la implementación de Factory en conecciones, muchos de mis colegas comentan que requiere tiempo desarrollar algo así, pero si lo he implementado en funcionalidad para usuarios,como control de roles en un sistema… es una buena plicación bueno creo yo.
    Gran aporte compañero Felicidades.

    1. Gracias amigo.
      Este solo es un ejemplo y no es exclusivo para conexiones a base de datos, sin embargo se me hace un ejemplo muy practico para que todos podamos entender de que se trata.
      Con respecto al tiempo de desarrollo, yo creo que el tiempo de desarrollo es algo absurdo cuando los beneficios son mucho mas grandes y es que los patrones de diseño están diseñados para que nuestra aplicación se mucho mas fácil de mantener.

      Saludos

  2. Hola.

    La definición UML del patrón de diseño y y el código no resultan consecuentes, pues una fábrica concreta debe tener una fábrica abstracta que implemente el método definido en la abstracta.

    1. Hola Walter, lo que dices tiene sentido, pues esperas que el código refleja exactamente el diagrama, sin embargo, el factory abstracto es opcional, ya que no es necesario para implementar el patrón. En el diagrama UML se muestra por que es un componente que puede estar, aun que no es una regla.

      El motivo por el cual tenemos un Factory Abstracto, es para poder tener funcionalidad predefinida y reutilizable en caso de que exista más de un Factory.

      Espero que esta respuesta sirva de algo.
      Saludos.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *