El siguiente de los patrones que vamos a revisar es el de “Factory Method”. En este caso, como podéis ver, el nombre 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 considerar que el patrón “Factor Method” es una simplificación del patrón de “Abstract Factory”. En mi caso concreto, hasta empezar a leer el libro, no hacía ninguna distinción entre uno y otro, para mi eran algo así como: una factoría compleja (Abstract Factory), y una factoría simple (Factory Method). Y es aquí donde vemos un nuevo ejemplo de la importancia en muchas ocasiones de saber como llamar de forma correcta aquello que sabemos.
Sin más rodeos, vamos a empezar.
El patrón “Factory Method” se define como una interfaz para la creación de cierto tipo de objeto, permitiendo que las subclases decidan que clase concreta necesitan instanciar. El problema que se plantea en algunos entornos es que una clase no puede anticipar el tipo de objetos que debe crear debido a la jerarquía de clases existente, lo cual provoca que tenga que delegar esta tarea en una subclase.
Por decir lo de una forma menos intrincada, viene a solucionar el problema que se presenta cuando tenemos que crear la instancia de un objeto pero a priori no sabemos aún que tipo de objeto tiene que ser, generalmente, porque depende de alguna opción que seleccione el usuario en la aplicación o porque depende de una configuración que se hace en tiempo de despliegue de la aplicación.
Este patrón se compone de:
- Product: Define la interfaz de los objetos que de van a crear.
- ConcreteProduct: Implementación de la interfaz.
- Creator: Declara la factoría y devuelve un objeto del tipo producto. Además, puede definir una implementación por defecto para la factoria que devolvería un objeto ConcreteProduct por defecto.
- ConcreteCreator: Sobreescribe el método de la factoría para devolver una instancia concreta de un objeto ConcreteProduct.
A la hora de la implementación tenemos varias opciones disponibles:
- El Creator es una clase abstracta y no ofrece ningún tipo de implementación para la factoría que declara. (Ejemplo 1)
- El Creator es una clase concreta y ofrece una implementación por defecto de la factoría.
- La parametrización de la factoría. Donde la factoría recibe un parámetro con el tipo de objeto que tiene que crear. Todos los objetos disponibles tiene que compartir la interfaz Product. (Ejemplo 2)
No teniendo mucho más que describir, vamos a pasar al ejemplo, donde yo creo que entenderemos mejor todo esto. Como tenemos varias formas posibles de implementación y este yo creo que, junto con el patrón Singleton (que ya veremos), es uno de los patrones que más se utilizan en Frameworks y desarrollos, vamos a ver dos ejemplos. El primero de los tipos vistos más arriba y el parametrizado.
Ejemplo 1: Clase abstracta sin implementación por defecto.
Creator:
public abstract class DBManager { public abstract DB factoryMethod(); }
ConcreteCreator:
public class MySQLDBManager extends DBManager { protected DB factoryMethod() { return new MySQLDB(); } } public class OracleDBManager extends DBManager { protected DB factoryMethod() { return new OracleDB(); } }
Product:
public interface DB { public void operation(); }
ConcreteProduct:
public class MySQLDB implements DB { public void operation() { System.out.println(“Soy MySQL”); } } public class OracleDB implements DB { public void operation() { System.out.println(“Soy Oracle”); } }
Main:
public class Main { public static void main(String[] args) { DBManager manager = new MySQLDBManager(); MySQLDB mysql = manager.factoryMethod(); mysql.operation(); manager = new OracleBDManager(); OracleDB oracle = manager.factoryMethod(); oracle.operation(); } }
Ejemplo 2: Factoría parametrizada.
Creator and ConcreteCreator:
public class DBManager { public static DB createDBConnection(String descriptor) { if (“Oracle”.equals(descriptor)) { return OracleDB(); } else if (“MySQL”.equals(descriptor)) { return MySQLDB(); } else { … } } }
Product:
public interface DB { public void operation(); }
ConcreteProduct:
public class MySQLDB implements DB { public void operation(){ System.out.println(“Soy MySQL”); } } public class OracleDB implements DB { public void operation(){ System.out.println(“Soy Oracle”); } }
Main:
public class Main { public static void main(String[] args) { DB dataBase = DBManager. createDBConnection(“MySQL”); dataBase.operation(); dataBase = DBManager. createDBConnection(“Oracle”); dataBase.operation(); } }
Ya tenemos una más. Espero que hasta aquí esté siendo todo claro. Dentro de poco la siguiente entrega. Nos vemos.
Muchas gracias por plantearlo pero seria bueno que dejases un “ejemplo problema” y como solucionarlo utilizando el patrón.
LikeLike
el ejercicio1 no compila!
LikeLike
en el main debería ser: DBManager manager = new MySQLDBManager();
MySQLDB mysql = (MySQLDB)manager.factoryMethod();
mysql.operation();
manager = new OracleDBManager();
OracleDB oracle = (OracleDB)manager.factoryMethod();
oracle.operation();
y los métodos factory como public… ahí compila.. saludos!
LikeLike
El ejemplo 2 no compila
LikeLike