El patrón de diseño de Fábrica pertenece a la categoría de Patrones de Creación. Los patrones de diseño de creación buscan obtener la mejor forma de crear un objeto con miras en la reutilización y la flexibilidad de cara al futuro.
En esta oportunidad se estudiará los beneficios y contras de aplicar el patrón de fábrica, los casos en que debe utilizarse y se ilustrará con un ejemplo práctico en Java.
Definición
El patrón Fábrica propone utilizar una instancia como fábrica de objetos. Esta fábrica puede estar en capacidad de devolver una instancia de clase de entre varias posibles (jerarquías de subclases) según los datos provistos a la misma.
¿Cuándo usarlo?
- Cuando una clase no puede saber de forma anticipada que objeto debe crear.
- Se desea adaptar y conocer los datos de la clase que se esta creando.
- Para utilizar clases que heredan de otras clases o implementan la misma interfaz y por tanto tienen métodos compartidos que pueden utilizarse indistintamente.
- Cuando se desea aislar al cliente del tipo de clase que se va a crear.
Beneficios
- El cliente no necesita conocer todas las instancias de subclase que debe implementar. Solo se necesita una referencia a la clase abstracta o interfaz.
- La fábrica permite encapsular la creación de objetos, lo cual puede ser muy útil para procesos de negocio complejos.
Inconvenientes y Consecuencias
- No hay manera de cambiar una clase o adicionar una nueva sin volver a compilar. A menos que se utilize la inyección de dependencias.
Estructura
Ejemplo en Java
Para este ejemplo, la fábrica creará dos clases concretas: el producto A y el producto B. Ambos productos comparten el método «escribirNombre» y cada uno lo implementa a su forma. El producto A escribe su nombre tal cual y el producto B lo escribe en reverso.
Clase abstracta producto
public abstract class Producto { protected void escribirNombre (String nombre) { System.out.println("Mi nombre es: " + nombre); } }
Clase concreta para el producto A
public class ProductoA extends Producto { }
Clase concreta para el producto B
public class ProductoB extends Producto { @Override public void escribirNombre(String nombre) { StringBuilder nombreTemporal = new StringBuilder().append(nombre); System.out.println("Mi nombre en reversa es: " + nombreTemporal.reverse()); } }
Tipo enumerado para clasificar los productos
public enum TipoProducto { PRODUCTO_A, PRODUCTO_B }
Clase de la fábrica:
public class FabricaProducto { public Producto crearProducto(TipoProducto tipo) { switch (tipo) { case PRODUCTO_A: return new ProductoA(); case PRODUCTO_B: return new ProductoB(); default: return null; } } }
Clase de prueba desde el cliente
public class ClienteTest { public static void main(String[] args) { FabricaProducto fp = new FabricaProducto(); Producto prod; prod = fp.crearProducto(TipoProducto.PRODUCTO_A); prod.escribirNombre("Gerardo"); prod = fp.crearProducto(TipoProducto.PRODUCTO_B); prod.escribirNombre("Gerardo"); } }
Salida por consola tras la ejecución:
Descargar código en archivo .zip
Referencias
Benneth Christiansson et al. GoF Design Patterns – with examples using Java and UML2. 2008 Creative Commons Attribution-ShareAlike 3.0 License