Organizar el código nos va a ahorrar mucho dolor. Usando las características de la programación orientada a objetos, podemos emplear ciertos patrones de diseño para lograr una mejor legibilidad, reducir la redundancia y crear abstracciones, si es necesario. Uno de estos patrones es el patrón de fábrica.
El patrón de fábrica es un tipo de patrón orientado a objetos que sigue la metodología DRY. Como su nombre indica, las instancias de los objetos se crean utilizando una fábrica para hacer el objeto requerido por nosotros.
Veamos un ejemplo muy sencillo de cómo utilizar el patrón de fábrica para montar un objeto alligator
. Para ello, primero tenemos que hacer las fábricas que crean las piezas alligator
para nosotros:
class TailFactory { constructor(props) { this.tailLength = props.tailLength; }};class TorsoFactory { constructor(props) { this.color = props.color; }};class HeadFactory { constructor(props) { this.snoutLenth = props.snoutLenth; }};
Ahora, creamos una clase que actúa como un intermediario entre las clases reales de las fábricas y el usuario. Llamémosla ReptilePartFactory
:
class ReptilePartFactory { constructor(type, props) { if(type === "tail") return new TailFactory(props); if(type === "torso") return new TorsoFactory(props); if(type === "head") return new HeadFactory(props); }};
Ahora vamos a montar el caimán real y usaremos la ReptilePartFactory
para obtener las partes necesarias para nosotros:
let alligator = {};let alligatorProps = { tailLength : 2.5, color: "green", snoutLenth: 1};//gets a tail from the tail factoryalligator.tail = new ReptilePartFactory("tail", alligatorProps); //gets a torso from the torso factoryalligator.torso = new ReptilePartFactory("torso", alligatorProps);//gets a head from the head factoryalligator.head = new ReptilePartFactory("head", alligatorProps);
Al ver el patrón anterior, parece que podríamos usar la misma ReptilePartFactory
para crear partes para los objetos tipo caimán. Las fábricas en segundo plano nunca tendrían que conocer la naturaleza del objeto final.
Así, utilizar el patrón de fábrica nos da ciertas ventajas:
- Creación dinámica de objetos: Se puede utilizar en casos en los que el tipo del objeto se decide en tiempo de ejecución.
- Abstracción: El usuario nunca tiene que acceder realmente al constructor del objeto real.
- Reusabilidad/Mantenimiento: Las mismas fábricas se pueden utilizar para objetos similares y nos permite añadir/eliminar nuevas clases de objetos fácilmente sin cambiar mucho código.
Ahora que tenemos una cierta comprensión del patrón de fábrica, vamos a explorar un poco en la escritura de un mejor código de patrón de fábrica.
El ejemplo anterior utiliza un if-ladder para averiguar qué fábrica llamar en base a la entrada del usuario. Esta es una implementación simple, intuitiva y no muy abierta a cambios. Si tenemos nuevas partes que añadir más tarde, entonces tendríamos que alterar el ReptilePartFactory
. Esto es una violación de los principios SOLID, que establece «Las entidades de software (clases, módulos, funciones, etc.) deben estar abiertas para la extensión, pero cerradas para la modificación».
¿Qué tal si almacenamos las clases de fábrica en un objeto y llamamos a la fábrica de partes requerida usando la parte que queremos como clave? Primero tendríamos que registrar las fábricas, sería tan sencillo como:
let registeredPartFactories = {};registeredPartFactories = class TailFactory{ ...};registeredPartFactories = class TorsoFactory { ...};registeredPartFactories = class HeadFactory { ...};
Y ahora, la capa abstracta puede llamar a las fábricas así:
class ReptilePartFactory { constructor(type, props) { return new registeredPartFactories(props); }};
Este enfoque es mucho más limpio y permite ampliar nuestras fábricas sin afectar al código en el ReptilePartFactory
.
En conclusión
Hay varios otros patrones orientados a objetos que también aumentan la legibilidad y la calidad. Así que antes de usar el patrón de fábrica, comprueba si hay un requisito real para ello. Si vas a crear tipos de objetos similares repetidamente y también necesitas una capa para crear nuevas instancias usando estos objetos mientras proporcionas algún nivel de abstracción a la lógica de creación, entonces sí – el patrón de fábrica es una buena opción.