DEV Community

Miguel Ángel Sánchez Chordi
Miguel Ángel Sánchez Chordi

Posted on • Originally published at Medium on

Patrón Factory

Introducción

En el post sobre patrones de diseño de software vimos que estos se podían agrupar en tres grandes grupos: creacionales, estructurales y de comportamiento. En este post vamos a profundizar con el patrón factory , que pertenece al grupo de patrones creacionales, y vamos a a ver su implementación, casos de uso y ventajas e inconvenientes.

Importante: No confundir el patrón Factory con el patrón Abstract Factory, aunque del mismo tipo, resuelven distintos problemas de distinta forma.

Propósito

Como todo patrón creacional, su cometido radica en solucionar problemas con la creación o instanciación de objetos. En este caso el patrón factory pretende ocultar al cliente los detalles de instanciación de ciertos objetos, o dicho de otra forma:

Desacoplar la lógica de creación de la lógica de negocio, evitando al cliente conocer detalles de la instanciación de los objetos de los que depende.

Implementación

Caso de ejemplo

Vamos a imaginar que estamos programando un panel informativo de un concesionario, de forma que al pulsar sobre uno de los modelos nos muestra su ficha informativa. El código podría ser algo así:

Este ejemplo tiene claros problemas, y el principal es el switch encargado de gestionar los datos del vehículo.

El problema va más allá, ya que si cualquier otra clase necesita esta información, se ve obligada a replicar este tedioso switch, y si algún día esta lista cambia, habrá que editar todos estos switch, ya que todas estas clases están incumpliendo el SRP y el OCP, ya que hay más de un motivo de cambio para estas clases y es necesario modificarlas para extender su funcionalidad.

Implementando el patrón

Los pasos a seguir para implementar en este caso el patrón Factory son:

  • Encapsular en objetos la información relativa al vehículo. No tiene sentido tener esas variables sueltas dentro del switch.
  • Hacer que todos los objetos implementen la misma interfaz. Puesto que la información es la misma, es mejor que todos implementen una misma interfaz.
  • Extraer la lógica de creación a una factoría. El cliente (el panel informativo en este caso) no tiene por qué conocer como se instancian estos objetos, no es su responsabilidad, y además no es reutilizable. Saquemos ese código a una clase nueva.
  • Usar la factoría en el panel informativo. Hagamos uso de la factoría en el cliente.

Como se puede observar ahora:

  • Hemos definido la interfaz CarInfoInterface, que define los getters necesarios para obtener la información del vehículo.
  • Se ha creado una clase por cada uno de los modelos de coche disponibles.
  • Hemos creado una clase CarFactory que se encarga de construir el vehículo adecuado para cada código y de lanzar una excepción en caso de no existir ningún vehículo asociado al código.
  • El cliente CarInformation ahora recibe en el constructor la factoría y hace uso de ella para obtener un objeto que implementa CarInfoInterface con el que muestra el título adecuado.

Ventajas

  • La factoría es altamente reutilizable, solo hay que pasarla como dependencia.
  • El testing del cliente es mucho más sencillo, podemos usar mocks para la factoría y simular cualquier tipo de repuesta por parte de la misma, permitiendo testear todos los casos de uso posibles.
  • Si queremos añadir un nuevo vehículo, solo hay que editar la factoría y añadirlo ahí, pasará a estar disponible para todos los usuarios de la factoría sin tener que replicar código.

Inconvenientes

  • En este ejemplo , si la cantidad de opciones crece en exceso, la factoría puede llegar a ser una clase difícil de mantener y habría que encontrar otras alternativas al switch.

Conclusión

Abstraer al cliente de la creación de los objetos de los que depende es un principio básico en la creación de software de calidad. Esto nos permite cumplir con dos principios SOLID de un plumazo y además seguir uno de los principios de la programación orientada a objetos: la encapsulación de los datos en objetos.

Espero que os haya gustado este post, nos vemos en el siguiente! ;)


Latest comments (0)