Entrando en materia vamos a empezar con los patrones. Para todo aquel que esté intentando seguir el libro, observará que me he saltado una sección, más concretamente, la del caso de estudio. Aunque la sección no está mal ni mucho menos (me la he leído únicamente por encima), creo que no tiene lugar en el objetivo de esta serie de artículos, y por este motivo, la he saltado. Pero os animo a que si estáis siguiendo el libro, hagáis una pequeña pausa antes de continuar leyendo este artículo y os lo leáis antes de seguir.
El primero de los patrones que vamos a ver es el “Abstract Factory”.
Simplificando mucho el concepto para que de cara al futuro nos quede aunque sea una idea clave en la cabeza sobre qué es este patrón, podemos decir que una Abstract Factory es una clase que nos provee de una interfaz para producir una familia de objetos. Lo que a todos los efectos es, crear una interfaz que nos permita la creación y utilización de objetos relacionados pero sin tener que definir ni especificar una clase concreta. Se suele utilizar mucho por ejemplo para la creación de widgets o interfaces gráficas que sean multiplataforma, de esta forma nos podemos abstraer del sistema concreto y realizar el desarrollo de forma genérica. Otro nombre que recibe es el de “Kit”. Personalmente, nunca había oído este nombre, pero en el libro aparece y no está de más nombrarlo (lo que dije al principio, hay que saber cómo se nombran las cosas y no solo que son). Lo que busca el patrón es ofrecer la posibilidad de trabajar con varios objetos diferentes aunque relacionados y facilitar la adhesión de nuevos objetos relacionados en un futuro para cubrir nuevas necesidades.
Como ejemplo, vamos a coger el mencionado sistema de widgets para la creación de una aplicación cliente. El problema al que nos enfrentamos a la hora de realizar una implementación, es que queremos soportar múltiples estándares, y en un futuro, quizás, añadir nuevos. Con esto la aplicación cliente no puede crear un objeto concreto:
StndAMenuBar nemu = new StdnAMenuBar();
Las aplicaciones clientes deberían trabajar con objetos y clases genéricas abstrayéndose de la implementación concreta:
MenuBar menu = Menu.createMenuBar();
De esta forma, conseguiremos que nuestro sistema sea:
- Independiente de los procesos de creación, composición y representación de sus productos.
- Configurable para una familia de productos
- Solo necesitará proporcionar una librería de productos y no su implementación.
Así los elementos en nuestro desarrollo serán:
- AbstractFactory: Interfaz para las operaciones de creación de productos abstractos.
- ConcreteFactory: Implementa las operaciones para la creación de objetos de productos concretos
- AbstractProduct: Declara una interfaz para los objetos de un tipo de productos.
- ConcreteProduct: Define un objeto de producto que creará la correspondiente Concrete Factory , a la vez que implementa la interfaz de AbstractProduct.
- Client: Será el que utilice nuestras clases abstractas.
Lo se, no os habéis enterado de nada y estáis mirando el monitor con cara de pocos amigos. No os preocupéis, seguid en vuestra mente con la frase inicial que dijimos íbamos a recordar y repasad este apartado de nuevo cuando estéis viendo el ejemplo de código.
Pero antes de pasar al código, solo un par de anotaciones sobre algunas ventajas y desventajas.
Ventajas:
- Aísla las clases de implementación: ayuda a controlar los objetos que se creen y encapsula la responsabilidad y el proceso de creación de objetos producto.
- Hace fácil el intercambio de familias de productos. Solo necesitaremos cambiar de factory.
- Fomenta la consistencia entre productos.
Desventajas:
- Para añadir un nuevo productos, se requiere la implementación de el interfaz y todos sus métodos.
Y por fin hemos llegado al código. Vamos a implementar una pequeña imprenta y los servicios que esta ofrece: Impresión a color, impresión en blanco y negro, y diseño de carteles.
Para ello vamos a implementar en primer lugar nuestro interfaz que implementarán nuestros diferentes servicios:
public interface Servicio { public void codigoDeServicio(); }
Ahora vamos a crear la interfaz encargada de la creación de servicios:
public interface ServicioDeImpresion { public Servicio crearServicio(); }
Ahora crearemos los tres servicios que ofrece nuestra imprenta:
public class ServicioColor implements Servicio { public void codigoDeServicio() { return COLOR; } } public class ServicioBandW implements Servicio { public void codigoDeServicio() { return B_AND_W; } } public class ServicioDesign implements Servicio { public void codigoDeServicio() { return DESIGN; } }
Ahora vamos a crear las Factory para cada uno de los servicios:
public class ColorFactory implements ServicioDeImpresion { public Servicio crearServicio() { return new ServicioColor(); } } public class BandWFactory implements ServicioDeImpresion { public Servicio crearServicio() { return new ServicioBandW(); } } public class DesignFactory implements ServicioDeImpresion { public Servicio crearServicio() { return new ServicioDesign(); } }
Finalmente, lo utilizamos en un ejemplo que creará una Factory del tipo que le pasemos como parámetro:
public class MainFactory { public static void createFactory(ServicioDeImpresion factoria) { Servicio s = factoria.crearServicio(); int c = s.codigoDeServicio(); ... } }
Con esto tendríamos implementado nuestro patrón Abstract Factory.
Buenos, espero que os hayáis aclarado, si tenéis cualquier duda, ya sabéis, dejad un comentario. Nos vemos.
[…] es bastante similar a uno de los patrones ya vistos en esta serie de artículos, este sería el “Abstract Factory”. A parte del nombre, existen entre ambos patrones varias similitudes más, de hecho, se puede […]
LikeLike
Lo último no entendí muy bien, exactamente cuando dice que se encapsula todo en una Factory y que se crea otra Factory.
Creo que lo estoy entendiendo mal: MainFactory es una clase para probar todo lo que se ha creado, pero en sí no es una Factory, ¿verdad?
Y por otro lado, creo que debería haber sido “… que creará un Servicio, según la clase concreta de Factory que se le pase como argumento”.
Gracias por la información, y estaría también agradecido a que me ayude con estas dudas. Debo realizar una exposición.
LikeLike
Hola. Quizás los nombre no sean los más intuitivos, pero es lo pasa a veces al tratar de traducir pasar a español unas ideas que te has hecho en inglés.
Tienes razón, lo corrijo ahora porque sí que pude dar lugar a errores. Las Factorías son las creadas previamente.
Sobre lo segundo, el servicio se crea porque los métodos de las distintas factorías se llaman así pero podían haber se llamado “ObtenerServicio”, “CrearLogica”, “HacerTarea”, … Realmente lo que se crea es una instancia del objeto que deseamos manejar.
LikeLike
Hola
Este ejemplo y el que pones en Factory Method ahora mismo me parecen los mismos, no encuentro las diferencias.
La clase equivalente a producto (DB) sería “Servicio”
las clases equivalentes a los productos concretos (MySQLDB y OracleDB) serían “ServicioColor”, “ServicioBandW” y “ServicioDesign”
La clase creadora (DBManager) sería equivalente a la clase “ServicioDeImpresion”
Las clases equivalentes a las creadoras concretas (MySQLDBManager, OracleDBManager) serían “ColorFactory”, “BandWFactory”, “DesignFactory”
Corrígeme si me me equivoco pero por lo que he estado viendo en los diagramas de la sección de la wikipedia, la diferencia real es que las factorías abstractas tienen más de una familia de productos (AbstractProducts) y cada implementación de la factoría te genera los ConcreteProducts que, estando en familias distintas, trabajan juntos,
Ejemplo un poco más practico la factoría abstracta aplicadas en a un “servicio de impresión” esta tendría dos implementaciones dependiendo si la impresión es “normal” o “fotográfica” estas factorías concretas generarían el producto concreto “tinta normal” o “tinta fotográfica” correspondiente al producto abstracto “tinta” y “papel normal” y “papel fotográfico” correspondiente al producto abstracto “papel”. El el patrón método factoría no existen varios productos, habría una factoría para papel y otra para tinta
Para resumir se podría decir que factoría abstracta es la agregación de n metodos factorías en una sola clase para, de este modo, agrupar varios productos de distintas familias que tienen un fin común
¿Ves correcto esta forma de ver los patrones?
Un saludo
LikeLike
Lamentablemente, estos dos patrones se suelen confundir bastante, de hecho, mucha gente los intercambia. Leyendo tu explicación, me parece bastante correcta tu perspectiva. Al final, como frase resumen para establecer una diferencia, diríamos que: El patrón “Factory Method”, contiene un método para producir un tipo de producto relacionado con su tipo; y el “Abstract Factory”, produce una familia de tipos que están relacionados.
En nuestro caso, para el “Factory Method” dicho método es el “factoryMethod”. En el caso del “Abstract Factory”, son los objetos de tipo servicio los que se crean.
La principal diferencia, como ya he dicho y bien señalas tú, es la de un método frente a un objeto. Por lo demás, ambos patrones son muy similares.
Ahí alguna definición más como: “Factory Method”, una clase que aplaza ejecución de un objeto a las subclases; “Abstract Factory”, crea una familia de productos. Todas las definiciones como ves dan vueltas a lo mismo.
Espero que te sirva, si no, vuelve a preguntar e intento explicarlo desde otro punto de vista o actualizar el artículo con más descripciones. Un saludo.
LikeLike
Por mi parte todo claro,
Enhorabuena por el blog, lo conocí ayer y la verdad es que tienes artículos muy interesantes
Un saludo
LikeLike