# Propósito
El Abstract Factory define una interfaz para crear una familia de objetos relacionados o que dependen entre sí, sin especificar sus clases concretas.
# Problema
La necesidad de crear familias de productos que, idealmente, deben ser usados juntos, desacoplando el código de creación del código de los productos.
# Solución
La solución que propone el Abstract Factory es:
-
Definir una interfaz para la creación de cada familia de objetos: Crear una interfaz o método abstracto para la creación de familia de productos.
-
Delegar la creación a las subclases, fábricas concretas de cada familia de productos: Cada familia tendrá su propia implementación de estas interfaces.
# Estructura
# Participantes
-
FabricaAbstracta: Interfaz que declara un conjunto de métodos para crear cada uno de los productos abstractos.
-
FabricaConcreta: Implementa los métodos para crear los productos concretos.
-
ProductoAbstracto: Declara una interfaz para un tipo de objeto producto.
-
ProductoConcreto: Define un objeto producto que va a ser creado por la correspondiente fábrica concreta. Implementa la interfaz ProductoAbstracto.
-
Cliente: Sólo usa interfaces declaradas por las clases FabricaAbstracta y ProductoAbstracto.
# Cuándo Usarlo
Este patrón es recomendable cuando:
-
Un sistema debe ser independiente de cómo se crean, componen y representan los productos.
-
Cuando un sistema debe ser configurado con una de múltiples familias de productos.
# Ventajas
-
verified
Consistencia de Productos: Asegura que los productos que se crean son compatibles entre sí.
-
verified
Intercambiabilidad: Facilita el cambio entre diferentes familias de productos.
-
verified
Aislamiento: Separa los detalles de implementación de los productos del código cliente.
# Desventajas
-
warning
Complejidad: Puede aumentar la complejidad del código debido a la gran cantidad de clases e interfaces involucradas.
-
warning
Dificultad para agregar nueva familia: La interfaz fábrica abstracta fija los tipos de productos que se pueden crear, por lo que agregar nuevas familias implica cambiar esta interfaz y todas las subclases.
# Ejemplo: Interfaces Gráficas
Pensemos en un módulo de software de creación de interfaces gráficas. Debe estar preparado para funcionar en múltiples sistemas operativos (Windows, MacOS, Linux).
Cada sistema operativo tiene su propia manera de dibujar elementos, como ventanas, botones, cuadros de texto, menúes.
Problema
Los clientes deben poder crear cada familia de elementos correspondientes en base al sistema operativo que estén usando, desacoplando la creación del uso de los elementos.
Solución planteada
Implementamos un Abstract Factory que permite crear toda la familia de objetos para un determinado sistema operativo.
Por un lado las clases de creación correspondientes al Abstract Factory, los creadores concretos para Windows y para MacOS, y por otro las clases de Productos, correspondientes a botón (Button) y cuadro de texto (TextBox), cada una con sus propias implementaciones para Windows y MacOS.
# Código Java
Codificamos en Java lo que preparamos en el diagrama. Definimos interfaces para los elementos básicos de la interfaz de usuario:
interface Button {
void paint();
}
interface TextBox {
void render();
}
Creamos implementaciones específicas para cada sistema operativo:
class WindowsButton implements Button {
public void paint() {
System.out.println("Render a button in a Windows style");
}
}
class MacOSButton implements Button {
public void paint() {
System.out.println("Render a button in a MacOS style");
}
}
class WindowsTextBox implements TextBox {
public void render() {
System.out.println("Render a text box in a Windows style");
}
}
Definimos la interfaz para la fábrica abstracta y sus implementaciones:
interface GUIFactory {
Button createButton();
TextBox createTextBox();
}
class WindowsFactory implements GUIFactory {
public Button createButton() { return new WindowsButton(); }
public TextBox createTextBox() { return new WindowsTextBox(); }
}
El cliente usa la fábrica abstracta:
class Application {
private Button button;
private TextBox textBox;
public Application(GUIFactory factory) {
button = factory.createButton();
textBox = factory.createTextBox();
}
public void paint() {
button.paint();
textBox.render();
}
}
# Mapeo Participantes
-
GUIFactory (FabricaAbstracta): Interfaz para crear objetos Button y TextBox.
-
WindowsFactory, MacOSFactory (FabricaConcreta): Implementan la creación de la familia de productos para cada sistema operativo.
-
Button, TextBox (ProductoAbstracto): Interfaz de productos.
-
WindowsButton, MacOSButton, WindowsTextBox, MacOSTextBox (ProductoConcreto): Implementaciones específicas de cada producto para cada sistema operativo.
-
Application (Cliente): Usa la fábrica abstracta para crear y manipular objetos de tipo Button y TextBox.
# Conclusiones
Este ejemplo demuestra el uso del Abstract Factory para crear familias de objetos relacionados (botones y cuadros de texto). De esta manera podemos intercambiar fácilmente entre diferentes implementaciones (Windows y MacOS) sin cambiar el código del cliente.
# Patrones relacionados
Factory Method
Las clases FabricaAbstracta suelen implementarse con Factory Methods.
Prototype
Las fábricas abstractas también pueden implementarse usando prototipos.
Singleton
Las fábricas concretas suelen implementarse como Singletons.