En realidad son una familia de patrones:
Los dos últimos están incluidos en el catálogo del GoF

Estos patrones entran en la categoría de patrones de creación [GoF95], la cual comparten con otros patrones tales como el Singleton, Builder y Prototype [GoF95]. Tienen la responsabilidad de crear instancias de objetos de otras clases. Tienen además la responsabilidad y el conocimiento necesario para encapsular la forma en que se crean determinados tipos de objetos en una aplicación. Existen diferentes patrones de tipo Factory.
Como en todas las factorias, tenemos las clases instanciadas (JuegoDelDado y JuegoDeMoneda) que se relacionan con una clase madre (extends) o con un interfaz lógico (implements). En nuestro caso usamos interfaz.
A continuación puede ver un sencillo ejemplo en el que cada juego implementa el método lanzar(): el juego del dado muestra un número aleatorio del 1 al 6 y el de la moneda 'Cara' o 'Cruz':
public interface Juego {
void lanzar();
}
import java.util.Random;
public class JuegoDelDado implements Juego {
public void lanzar() {
Random ran = new Random();
int resul = ran.nextInt(6) + 1; // Aleatorio de 1 a 6
System.out.println( resul );
}
}
import java.util.Random;
public class JuegoDeMoneda implements Juego {
public void lanzar() {
Random ran = new Random();
if ( ran.nextBoolean() )
System.out.println( "Cara" );
else
System.out.println( "Cruz" );
}
}
La clase FactoriaJuegos es única. No delega en una subclase la creación de instancias (a diferencia de Factory Method). Esta factoria es muy sencilla: en función del argumento crea un juego u otro:
public class FactoriaJuegos {
public static Juego getJuego( String nombreJuego ) {
if ( nombreJuego.equals("JuegoDelDado") )
return new JuegoDelDado();
else {
if ( nombreJuego.equals("JuegoDeMoneda") )
return new JuegoDeMoneda();
else
return null;
}
}
}
Lo esencial de la clase Factoria es que oculta a la clase cliente (Inicio.java) la complejidad de crear un objeto. Encapsula la creacioón de la instancia.
La clase cliente (Inicio.java) llama al método estático getJuego() de la factoria, para que le devuelva el juego señalado en el argumento. Introduce todos los juegos en un vector y a continuación le dice a cada juego que juegue. El método jugar() es un ejemplo de patrón 'estrategia': el metodo contiene un comportamiento genérico (en nuestro ejemplo realiza dos lanzamientos para cada juego). El comportamiento específico se define en función del objeto que se pasa como argumento. La parte que varia es el argumento, esta es la estrategia.
public class Inicio {
public static void main(String[] args) {
//// Crea un vector de juegos
Vector vec = new Vector();
vec.add( FactoriaJuegos.getJuego( "JuegoDelDado") );
vec.add( FactoriaJuegos.getJuego( "JuegoDeMoneda") );
vec.add( FactoriaJuegos.getJuego( "JuegoDelDado") );
//// A cada juego del vector le dice que juegue
for ( int i = 0; i < vec.size(); i++ ) {
Juego j = (Juego) vec.get(i);
if ( j != null )
jugar( j );
else
System.out.println("Juego no encontrado");
}
}
/************************************************************************************
* Lanza dos veces
***********************************************************************************/
public static void jugar( Juego juego ) {
juego.lanzar();
juego.lanzar();
}
}
Al recorrer el vector de juegos vemos un ejemplo típico de polimorfismo: a cada referencia del tipo Juego (usamos el mismo interfaz) le decimos que juegue, pero cada juego implementa su forma específica de jugar (más en concreto de lanzar). Es la idea de polimorfismo: un interfaz y múltiples implementaciones.
Aunque la forma más abstracta y profesional es usar en la factoria newInstance() en función de los valores de un archivo .properties:
import java.io.*;
public class FactoriaJuegos {
// true=Carga de Properties desde archivo
private static boolean propiedadesCargadas = false;
// Propiedades
private static java.util.Properties prop = new java.util.Properties();
/***********************************************************************************
* Crea y devuelve el juego
**********************************************************************************/
public static Juego getJuego( String nombreJuego ) {
try {
//// La clase se consigue leyendo del archivo properties
Class clase = Class.forName( getClase( nombreJuego ) );
//// Creo una instancia
return (Juego) clase.newInstance();
}
catch (ClassNotFoundException e) { // No existe la clase
e.printStackTrace();
return null;
}
catch (Exception e) { // No puedo instanciar la clase
e.printStackTrace();
return null;
}
}
/***********************************************************************************
* Lee un archivo properties donde se indica la clase que debe ser instanciada
**********************************************************************************/
private static String getClase( String nombrePropiedad ) {
try {
//// Carga de propiedades desde archivo
if ( !propiedadesCargadas ) {
FileInputStream archivo = new FileInputStream( "src/factoriaJuegosNewInstanceProperties/propiedades.properties" );
prop.load( archivo ); // Cargo propiedades
propiedadesCargadas = true;
}
//// Lectura de propiedad
String nombreClase = prop.getProperty( nombrePropiedad, "");
if ( nombreClase.length() > 0)
return nombreClase;
return null;
}
catch ( FileNotFoundException e) { // No se puede encontrar archivo
e.printStackTrace();
return null;
}
catch ( IOException e) { // Falla load()
e.printStackTrace();
return null;
}
catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
En el archivo properties tenemos:
dado=factoriaJuegosNewInstanceProperties.JuegoDelDado moneda=factoriaJuegosNewInstanceProperties.JuegoDeMoneda