domingo, 8 de diciembre de 2019

Patrones creacionales: Builder, Factory Method y Singleton

Ya en el post sobre AutoValue estuvimos hablando de las distintas formas que había para poder crear una instancia de la clase. Donde hablabamos de las distintas formas que había de generar una instancia. Hoy hablaremos, basandonos en el famoso libro del Gang of Four sobre patrones creacionales. 
  • Builder
Se basa en permitir la creación de un objeto complejo en distintas etapas. Util y eficaz en contra posición a la implementación de un constructor con múltiples parámetros.

public class Car {
 private String wheels;
 private String motor;
 private String gas;
 // Getters and setters
}

Crearemos una inner class de utilidad que nos permita generar un objeto pero en etapas.

public class Car {
 // private fields, gettes and setters
public static class CarBuilder { private String wheels; private String motor; private String gas; public CarBuilder(final String motor) { this.motor = motor; } public Car build() { Car car = new Car(); car.motor = motor; car.gas = gas; car.wheels = wheels; return car; } public CarBuilder withGas(final String gas) { this.gas = gas; return this; } public CarBuilder withWheels(final String wheels) { this.wheels = wheels; return this; } } }
//..... Creation 
Car mercedes = new Car.CarBuilder("V8").withGas("diesel").withWheels("Michelin").build();


Este enfoque hoy en día es ampliamente utilizado por distintas librerías de utilidad como puede ser Wiremock, aquí puedes ver un ejemplo. Como veis es util si tenemos clases con atributos opcionales o con muchos atributos pero del mismo tipo, evitando así que nos equivoquemos a la hora de invocar el constructor e invertamos el orden correcto de los parámetros.
  • Factory Method
Este patrón se basa en la creación de distintos tipos de objetos a través de un método. Estos objetos tienen en común la implementación de una misma interfaz o clase abstracta.

Supongamos que tenemos la clase abstracta 'Animal' y dos implementaciones 'Dog' y 'Cat':

public abstract class Animal {
 public abstract String makeNoise();
}
// ......
public class Cat extends Animal {
 @Override
 public String makeNoise() {
  return "Cat says 'miau'";
 }
}
// ......
public class Dog extends Animal {
 @Override
 public String makeNoise() {
  return "dog says 'guau'";
 }
}

En base a esto, una clase que implementará el patrón Factory Method sería así:

public class AnimalFactory {
 public Animal getAnimal(final String typeOfAnimal) {
  Animal exit = null;
  if ("dog".equals(typeOfAnimal)) {
   exit = new Dog();
  } else if ("cat".equals(typeOfAnimal)) {
   exit = new Cat();
  }
  return exit;
 }
}
//..... Test ........
public static void main(final String[] args) {
 // print dog says 'guau'
 System.out.println(new AnimalFactory().getAnimal("dog").makeNoise());
}

Gracias a este patrón podremos manejar interfaces en vez de implementaciones, aumentando así el desacoplamiento y la abstración de nuestro codigo. Además aunque no es el caso de nuestro ejemplo, podremos tener importantes lógicas de creación de objetos localizadas en un único punto, mejorando así la eficiencia y consumo de recursos de la aplicación.
  • Singleton
Se basa en la idea de tener una única instancia del objeto. Muy utilizado para clases de utilidad. Para crear esa instancia lo podemos realizar de dos formas. O bien la creamos de forma estática en la clase al arrancar la JVM o de forma peresoza, es decir cuando se invoque por primera vez. Además todo Singleton cuenta con las siguientes caracteristicas:
  • Instancia  estática. 
  • Constructor privado. 
  • Clase con atributo final. 
public final class SingletonExample {
 private static SingletonExample INSTANCE;
 public static SingletonExample getInstance() {
  if (INSTANCE == null) {
   INSTANCE = new SingletonExample();
  }
  return INSTANCE;
 }
 private SingletonExample() {
 }
 // Lo invocariamos con SingletonExample.getInstance().doSomething();
 public void doSomething() {
  System.out.println("doing something");
 }
}

Además de estos tres, hay un par más de patrones creacionales que definimos brevemente:
  • Abstract Factory: Se basa en la idea de tener una factoria de creación de factorias que implementen el patrón Factory Method.
  • Prototype: Se basa en la clonación de objetos en pos de reducir el coste de la creación del mismo. 

No hay comentarios:

Publicar un comentario