Los patrones de creación se dividen en 2 grupos fundamentales:
- De clase: Emplea la herencia para variar la clase del objeto creado.
- Patrones: Factoría Abstracta y Constructor.
- De objeto: La creación es realizada por otro objeto (delegación).
- Patrones: Método Factoría, Prototipo y Singleton.
En este artículo definiremos el primer tipo de los Patrones de Creación de Clase, la Factoría Abstracta, siguiendo el esquema general que vimos en la entrega anterior.
Factoría Abstracta
Nombre: Abstract Factory
Problema y Contexto:
Crear diferentes familias de objetos abstrayéndonos de los detalles de su creación.
Se aplica cuando:
- Hay previsión de que se incluirán nuevas familias de objetos.
- Existe dependencia (teórica) entre los tipos de objetos.
Solución y Estructura:
La solución será elaborar una interfaz para crear familias de objetos relacionados sin especificar sus clases concretas.
La estructura es la siguiente:
Donde:
Cliente: Es el usuario de la factoría, y deberá elegir la factoría adecuada, es decir, lo que quiere es obtener una instancia de alguno de los productos (ProductoA, ProductoB).
AbstractFactory: Define las interfaces de las factorías, provee un método para la obtención de cada objeto que pueda crear (crearProductoA() y crearProductoB())
Factorías Concretas: Representan las diferentes familias de productos, proveen la instancia concreta que se encarga de crear.
Producto abstracto: Interfaz para productos genéricos. En el diagrama son ProductoA y ProductoB. El cliente trabaja directamente con esta interfaz, que será implementada por los diferentes productos concretos.
Producto concreto: Implementación específica de los diferentes productos.
Consecuencias:
- POSITIVAS:
- Flexibilidad al aislar las clases concretas.
- NEGATIVAS:
- Para añadir nuevas familias hay que modificar tanto las clases abstractas como las concretas.
Patrones Relacionados: Método Factoría (Factory Method)
Ejemplo:
Para entender todo esto mejor, trataremos un caso práctico en Java mediante un ejemplo. En el mismo, crearemos distintos tipos de coches (berlina, coupé y monovolumen) utilizando una Factoría Abstracta.
En primer lugar, partimos de una interfaz Coche que representará a cualquier tipo de coche y definirá las operaciones que cualquier coche puede realizar:
public interface Coche
{
public float getVelocidad();
public String getTipo();
public boolean arrancar();
public int incrementarMarcha();
public int decrementarMarcha();
public float acelerar();
public float frenar();
public void encenderLuces();
public void apagarLuces();
}
Cada vehículo concreto (berlina, coupé y monovolúmen) implementará esta interfaz. La implementación individual de cada tipo no es relevante para el ejemplo.
A continuación crearemos una interfaz Fabricante, que permitirá crear vehículos a toda clase que la implemente:
public interface Fabricante
{
public Coche crearCoche();
}
El siguiente paso es definir las fábricas. Dispondremos de una fábrica principal (la factoría abstracta) que se encargará de invocar a las fábricas concretas de cada tipo de vehículo. Evidentemente tendremos que definir dichas fábricas concretas que implementarán la clase Fabricante:
public class FabricaBerlinas implements Fabricante
{
public Coche crearCoche()
{
Berlina coche_berlina = new Berlina();
return coche_berlina;
}
}
public class FabricaCoupes implements Fabricante
{
public Coche crearCoche()
{
Coupe coche_coupe = new Coupe();
return coche_coupe;
}
}
public class FabricaMonovolumenes implements Fabricante
{
public Coche crearCoche()
{
Monovolumen coche_monovolumen = new Monovolumen();
return coche_monovolumen;
}
}
public class FactoriaAbstractaDeCoches
{
Fabricante fab;
public FactoriaAbstractaDeVehiculos(Fabricante fab)
{
this.fab=fab;
}
public void setFabrica(Fabricante fab)
{
this.fab=fab;
}
public Coche crearCoche()
{
return this.fab.crearCoche();
}
}
Bien, ya tenemos todos los elementos necesarios. Ahora vamos a proceder a utilizarlos en el main:
public static void main(String[] args)
{
FactoriaAbstractaDeCoches f;
Coche miCoche;
if(args[0].equals(“Berlina”))
{
f = new FactoriaAbstractaDeCoches(new FabricaBerlinas());
}
else if(args[0].equals(“Coupe”))
{
f = new FactoriaAbstractaDeCoches(new FabricaCoupes());
}
else if(args[0].equals(“Mono”))
{
f = new FactoriaAbstractaDeCoches(new FabricaMonovolumenes());
}
miCoche = f.crearCoche();
System.out.println(“Tengo un cohe tipo : ”+miCoche.getTipo());
}