Constructores semánticos
Tags: cleancode, php, namedconstructors, refactoring
Published: 2019-07-18 11:21:49

---
title: Constructores semánticos
published: true
description: 
tags: Clean Code,PHP,Named Constructors,Refactoring
---


![](https://cdn-images-1.medium.com/max/2000/1*EX7vNErwk_YeSEz1YUTQkw.png)

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:

 <iframe src="https://medium.com/media/98958c79884a46aa3ea7e377f3e7e8a8" frameborder=0></iframe>

Aquí vemos un pequeño [Value Object](https://martinfowler.com/bliki/ValueObject.html) 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:

 <iframe src="https://medium.com/media/767bab32e3225067c91da89ef63502a9" frameborder=0></iframe>

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:

 <iframe src="https://medium.com/media/de88a155312d59e41daf9a82e1b7122f" frameborder=0></iframe>

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.