El próposito principal de los patrones de creación consiste básicamente en la abstracción del procedimiento de creación de una nueva instancia de un objeto. Recordar que abstraer significa ocultar los detalles concretos de implementación, es decir, separar el qué del cómo, dejando únicamente al código que crea dicha instancia la necesidad de conocer la interfaz de creación pero no los detalles de como se crea la instancia del objeto.
Es decir, supongamos que tenemos una clase de objetos denominada ClaseObjeto. En ese caso el código que necesita crear una instancia de un objeto de esa clase, si lo hiciera de forma directa tendría el siguente aspecto:
ClaseObjeto referenciaInstancia = new ClaseObjeto();
Esta línea de código, que estaría situada en una determinada zona del código de la aplicación, hace que dicha parte no sea independiente de la manera en que se crean los objetos de tipo ClaseObjeto al hacer uso directo del operador new en su código.
El operador new requiere que se especifique la clase concreta de objeto a instanciar (y se le propocione una lista de argumentos que corresponda con alguna de las versiones de sobrecarga del constructor de objetos de la clase)
Con el uso directo del operador new se está codificando directamente el detalle de implementacion necesario para crear un nuevo objeto de esta clase, además del tipo concreto de objeto que se va que crear, dado que el operador new requiere que se le especifique una clase concreta.
La forma de abstraer el detalle de la creación de la nueva instacia en este código sería mediante un uso indirecto del operador new, sustituyéndolo en el código por la llamada a un método que se encargaría de realizar la operación new ClaseObjeto() en su lugar.
refenciaInstancia = creadorObjetos.metodoCrearObjeto(argumentos);
El método metodoCrearObjeto sería un método que encasula la operación new y devuelve la referencia a la instancia creada.
public class CreadorObjetos {
ClaseObjeto metodoCrearObjeto() {
return new ClaseObjeto();
}
}
Esté método dedicado a la creación de manera indirecta de instancias recibirá la denominación de método factoría, puesto que se encarga de «fabricar», cuando es invocado, una nueva instancia y devolver al código llamador una referencia a dicha instancia.
Vemos también a su vez que esté método puede formar parte de una clase CreadorObjetos que, dado que su cometido es la de proporcionar la posiblidad mediante la invocación de sus métodos de crear o fabricar instacias de objetos, recibirá la denominación de factoria o fabrica de objetos.
Veamos ahora que, si abstraemos una zona del código del detalle de la creación de instancias por el uso directo del operador new conseguiremos dos ventajas interesantes.
La primera es que en está parte del código no va a conocer el tipo o clase de objeto concreto con el que va a colaborar invocado a sus métodos una vez le sea devuelta la referencia a la instancia tras invocar al mótodo de fabricación de la factoria. Es decir, puede ser un tipo concreto de entre muchos que deriven de una misma clase común que llamaremos ObjetoAbstracto. En definiva el código solamente es conocedor de la interfaz para el uso de un objeto y pero no de la implementación concreta, lo que abre la puerta a la aplicación del polimorfismo, tanto el basado en herecia como el de interfaz.
Podemos ver esto facilmente en nuestro ejemplo si nos damos cuenta que podemos cambiar la linea 4 del código anterior por una …
return new ClaseObjetoConcreto();
siendo ClaseObjetoConcreto una clase de objetos que hereda o derive de ClaseObjeto (o lo que es lo mismo, un subtipo de ClaseObjeto).
En el código llamador no se necesita realizar ningun cambio para que pase a trabajar invocando los metodos de un tipo de objeto distinto y que por tanto puede tener una implementación diferente.
La segunda consiste en que la propia instancia de la factoría proporcionada a esa porción del código también puede ser una clase abstracta. Lo que implica nuevamente la posibilidad de aplicar el polimorfismo, esta vez respecto a la implementación concreta de la propia fábrica. Este proceso nos llevará camino del patrón Factoría Abstracta (Abstract Factory).
En resumen, la aplicación de un patrón de creación comienza con la sustición de la operacion directa de instanciación de objetos mediante el operador new por la llamada a un método virtual, con la consiguiente introducción en el código de una vía para la aplicación de polimorfismo al separar interfaz de implementación.
También hemos señalado que, por un lado, los patrones de creación encapsulan el conocimiento sobre las clases concretas que realmente se está usando en un sistema o parte del código. Además, por otro lado, ocultan como se crean (y se asocian) las instancias de estas clases fabricadas. Por lo tanto, todo lo que el código que hace uso de estos objetos conoce realmente son sus interfaces, (que pueden estar definidas mediante clases abstractas o interfaces de java u otro lenguaje orientado a objetos).
En definitiva, el uso de estos patrones introduce en el código la flexibilidad necesaria para poder variar lo que se crea, quien lo crea e incluso, como veremos, cuando se crea.