DEV Community

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

Posted on • Originally published at Medium on

Patrón Template Method

Introducción

El otro día estaba con un colega repasando un proyecto en el que iba a empezar a colaborar conmigo cuando empezamos a mirar una serie de clases que “olían” un poco raro: todas ellas tenían un fragmento de código que era literalmente igual en todas ellas.

Esta repetición de código no era casual: cada una de estas clases ejecutaba una validación de un array de entrada en base a un criterio, para ello usaba una librería de terceros que ayudaba a definir estos criterios y a detectar los errores. Luego trataba los errores de la validación para formar una excepción con todos ellos o bien devolvía true indicando que no había habido ninguna violación del criterio de validación.

Tenían un aspecto muy similar a este:

Básicamente todo el código desde la línea 62 hasta el final era código repetido en cada clase, pero al menos había tenido la decencia de usar un trait para reaprovechar el código que convertía las ConstraintViolation en mi formato de error.

Cuando mi colega vio esto me recordó el patrón Template Method y lo fácil y limpio que sería hacer un refactor, así que nos pusimos manos a la obra!

Template Method

El patrón Template Method es un patrón comportamental, esto quiere decir que es un patrón que nos ayuda a definir la forma en la que los objetos interactúan entre ellos..

Concretamente, este patrón define el esqueleto de la ejecución de un algoritmo, delegando la definición de uno o más pasos a distintas subclases, de tal forma que podemos tener tantas variaciones del mismo algoritmo como necesitemos, simplemente escribiendo las nuevas clases que redefinen esos pasos.

En este caso, la implementación del stepTwo queda delegada a las clases que implementan FrameworkClass

Veamos un ejemplo con un sistema de pago que permite pagar con Paypal y con Stripe:

En este caso, PaymentService es una clase abstracta, conoce todo el algoritmo de pago, excepto un caso que puede ser diferente en cada servicio: la forma de realizar el pago.

De esta forma, hemos dejado a implementar el pago a cada uno de los servicios, dejando el código restante en la clase abstracta (marcar factura como pagada y notificar al usuario del pago).

Refactoring de la clase del validador

Dicho esto, el refactor de nuestro validador era obvio: el único elemento cambiante eran las reglas de validación, así que extraeríamos el resto a una clase abstracta:

Incluso hemos podido prescindir el trait e integrarlo en la clase abstracta! Ahora todas nuestras clases de validación únicamente requieren implementar las reglas de validación, del resto se encarga la clase abstracta.


Discussion (0)