Hoy vamos a hablar de una práctica que mejorará visiblemente la calidad y la legibilidad de nuestro código.
Descripción
Constructores semánticos o named constructors es un pequeño refactor que consiste en eliminar la complejidad de los constructores cuando estos implican tener que conocer detalles de implementación del mismo.
Pongamos por ejemplo el siguiente código:
Aquí vemos un pequeño Value Object que representa un precio. El value object se compone de dos atributos, la cantidad y la divisa a usar.
Tal cual está montado, este value object nos obliga a conocer detalles de su implementación, como por ejemplo qué divisas soparte y cuáles no.
Implementación
Para aplicar el refactor de named constructors solo tenemos que seguir unos pocos pasos:
Convertir el constructor en privado
Crear uno o varios métodos estáticos que usando el constructor de la forma adecuada, devuelvan un nuevo objeto.
Darle a los nuevos métodos estáticos un nombre que describa su intencionalidad.
Sustituir las antiguas llamas al constructor por llamadas a los nuevos métodos estáticos
Comprobar que los tests pasan.
Veamos un ejemplo de este refactor:
Como se puede ver, el constructor ha pasado a ser privado y han aparecido 3 nuevos métodos:
createPriceInDollars
createPriceInPounds
createPriceInEuros
Y usarlos es así de sencillo:
$poundsPrice = Price::createPriceInPounds(22.5);
$dollarsPrice = Price::createPriceInDollars(22.5);
$eurosPrice = Price::createPriceInEuros(22.5);
Ahora, la interfaz pública del value object expone las distintas formas de crear un precio que soporta, con lo que el programador no debe de conocer detalles internos de su implementación.
Conclusión
Esto no deja de ser una variante de implementación del patrón Factory Method, en la que el método constructor se implementa en la misma clase y por tanto, ha de ser estático.
Su aplicación es realmente sencilla, y las ventajas son evidentes. Al estar utilizando métodos estáticos para construir los objetos se podría llegar a pensar que la testabilidad de estas clases quedaría comprometida, pero debido al ámbito de uso del mismo no suele generar problemas. Me explico: para testear estos métodos no se requiere (normalmente) el uso de mocks o stubs del método estático, lo cual es lo más crítico que nos podría pasar.
Para testear estos métodos simplemente podemos basarnos en que:
Devuelva un objeto de la clase adecuada
Se lancen excepciones si se da el caso de que debería de lanzarse
La información que hemos pasado al constructor se devuelve correctamente al acceder a los atributos adecuados a través de getters
Hay otro caso de uso en el que los named constructors son de utilidad, y es cuando deseamos tener más de un constructor, recibiendo obviamente diferentes parámetros. Esto en lenguajes que admiten sobrecarga de constructor como Java es muy sencillo de hacer, pero PHP no permite hacer esto.
La solución pasa por crear nuevos constructores semánticos que nos permitan implementar diferentes constructores con diferentes parámetros.
Veamos un caso:
Aquí hemos incorporado un segundo value object Amount que únicamente alberga un valor float.
Si quisiéramos que nuestro value object Price se pudiese construir a partir de un objeto Amount, en PHP no podemos hacer sobrecarga de constructor para añadir un segundo constructor que en lugar de un float reciba como parámetro un Amount, así que la solución pasa por añadir los métodos:
createPriceInPoundsFromAmount
createPriceInDollarsFromAmount
createPriceInEurosFromAmount
Como se puede ver, el nombre del método sigue reflejando claramente su intencionalidad.
Top comments (0)