El patrón Factory Method define una interfaz para crear objetos, pero deja que las subclases decidan qué clase instanciar. Se usa para abstraer la clase cliente sobre qué clase concreta usar, delegar la decisión de instanciación a las subclases, y desacoplar la complejidad de instanciación. Se provee un ejemplo donde se crean pelotas para diferentes deportes usando fábricas que instancian la pelota concreta correspondiente a cada deporte.
2. Intención
“Define an interface for creating an object, but
let subclasses decide which class to instantiate.
Factory Method let a class defer instantiation to
subclasses.”
Gamma et. al
4. ¿Cuándo usarlo?
● Abstraer a la clase cliente sobre qué clase concreta de
una familia tiene que usar.
● Delegar la decisión de qué clases se van a instanciar
en las clases hijas.
● Desacoplar la complejidad de la instanciación.
● Como alternativa a los constructores (Static FM).
● Para hacer más extensible la arquitectura.
5. Pero no debemos usarlo siempre
Como todos los patrones: no se debe forzar su uso si no es
necesario.
● Necesitamos una familia de objetos sobre los que
trabajar
● Puede aumentar la complejidad de la aplicación
introduciendo más niveles de indirección.
● No caer en la tentación de aplicarlo por si en el futuro
es necesario.
6. Tipos de Implementación
En general hay 4 tipos de implementación
1. Factoría padre abstracta que delega siempre en las
Factorías hijas.
2. Factoría padre que devuelve valor por defecto y casos
especiales en Factorías Hijas.
3. Factoría padre con tipo por parámetro.
Y también:
4. Variante: Static Factory Method.
7. Ejemplo
Familia de productos “Pelota” para diferentes
deportes.
public abstract class Pelota {
float diametro;
float peso;
String material;
public abstract String getTipo();
//Getters y Setters...
}
public class BaloncestoPelota extends Pelota {
public String getTipo() {
return "pelota de Baloncesto";
}
}
public class FutbolPelota extends Pelota {
public String getTipo() {
return "una pelota de fútbol";
}
}
public class TenisPelota extends Pelota {
public String getTipo() {
return "pelota de tenis";
}
}
public class GenericaPelota extends Pelota {
public String getTipo() {
return "pelota genérica";
}
}
8. Ejemplo
Deportistas a los que asignar una pelota para
su deporte.
public class Deportista {
String nombre;
Pelota pelota;
public Deportista(String nombre) {
this.nombre = nombre;
}
public String getSaludo() {
return "Hola, soy " + getNombre() + " y juego con una pelota de "
+ getPelota().getTipo() + " que pesa " + getPelota().getPeso()
+ " gramos";
}
//Getters y Setters...
}
9. Ejemplo
Familia de fábricas que construyen productos
pelota concreta en cada método (tipo 1)
public interface FactoryPelotas {
public Pelota create();
}
public class FactoryBaloncestoPelotas implements
FactoryPelotas {
public Pelota create() {
return new BaloncestoPelota();
}
}
public class FactoryFutbolPelotas implements
FactoryPelotas {
public Pelota create() {
return new FutbolPelota();
}
}
public class FactoryTenisPelotas implements
FactoryPelotas {
public Pelota create() {
return new TenisPelota();
}
}
10. Ejemplo
Main (Cliente que usa productos)
public class main {
public static void main(String[] args) {
ArrayList<Deportista> deportistas = new ArrayList<Deportista>();
// Definición de deportistas
Deportista baloncestoDep = new Deportista("Gasol");
Deportista futbolDep = new Deportista("Messi");
Deportista tenisDep = new Deportista("Nadal");
// Fábricas concretas
baloncestoDep.setPelota(new FactoryBaloncestoPelotas().create());
futbolDep.setPelota(new FactoryFutbolPelotas().create());
tenisDep.setPelota(new FactoryTenisPelotas().create());
deportistas.add(baloncestoDep);
deportistas.add(futbolDep);
deportistas.add(tenisDep);
for (Deportista dep : deportistas) {
dep.getPelota().setPeso((float) Math.random() * 500);
System.out.println( dep.getSaludo());
}}
}
11. Factory con parámetro (tipo 3)
public class FactoryParamPelotas {
public static Pelota create(TipoPelota tipo) {
Pelota salida;
switch (tipo) {
case BALONCESTO:
salida = new BaloncestoPelota();
break;
case TENIS:
salida = new TenisPelota();
break;
case FUTBOL:
salida = new FutbolPelota();
break;
default:
salida = new GenericaPelota();
break;
}
return salida;
}
}
……
baloncestoDep.setPelota( FactoryParamPelotas.create(TipoPelota.BALONCESTO));
baloncestoDep.setPelota( FactoryParamPelotas.create(TipoPelota.FUTBOL));
baloncestoDep.setPelota( FactoryParamPelotas.create(TipoPelota.TENIS));
12. Static Factory Method
Método estático que sustituye al constructor
Foo x = new Foo();
vs.
Foo x = Foo.create();
...o usando parámetros en la superclase
Foo x = Foo.create(tipo1);
también mejora la legibilidad del código
Punto punto = new Punto(x,y, sistemaMedicion);
si lo cambiamos por
Punto punto = Punto.createByMetros(x,y);
Punto punto2 = Punto.createByInches(x,y);