Patrón de diseño Builder en Java

Patrón Builder

Patrón Builder


Siguiendo con los patrones de diseño en Java, vamos a ver como podemos construir y hacer uso del Patrón Builder, el cual se encuentra dentro de los patrones de diseño creacionales.

La idea detrás del patrón Builder es poder construir estructuras complejas paso a paso. De manera que podemos utilizar diferentes tipos y representaciones de un objeto haciendo uso de la misma construcción.

Cuándo usar el Patrón Builder

En algunas ocasiones cuando nos encontremos construyendo una aplicación, vamos a necesitar crear clases en la que tengamos multitud de objetos que tendremos que inicializar e incluso quizás algún objeto anidado o campos que el objeto puede tener o no etc…

Lo más fácil para entenderlo es poner un ejemplo con la configuración de un coche.

Queremos comprar un coche, que tenga puertas, música, ruedas, etc…, es decir, lo necesario para que funcione, pero qué sucede si además le queremos añadir que sea descapotable, que corra más, que sea eléctrico y que no use gasolina, que las ruedas sean más grandes?. Aquí tendríamos que añadir más campos al constructor para poder inicializar, y no siempre queremos todos esos campos.

Qué podemos hacer? para poder tener flexibilidad en nuestro objeto coche y poder ampliar fácilmente a nuevas características, aplicar el patrón Builder

Cómo aplicar el Patrón Builder

El patrón de diseño Builder lo que intenta es sacar las partes del objeto complejo fuera de la clase principal y moverlo a diferentes objetos que llamamos builders.

Este patrón nos va a ayudar a construir nuestro objeto final en pequeños pasos. De manera, que utilizaremos solo lo que necesitamos para nuestro objeto.

Entity Car

Ahora para nuestro coche vamos a tener diversas configuraciones por lo que en función del requerimiento del cliente que va a comprar un coche podemos añadir rápidamente una funcionalidad extra.

Para implementar este patrón podemos hacer uso o NO, de una característica adicional, del DIRECTOR o Coordinador. El cual se encargará de definir la secuencia de pasos para llevar a cabo la construcción.

Implementación de Patrón Builder

A continuación se muestra el diagrama de como implementar el patrón Builder, el dibujo siguiente hemos añadido un director, pero como hemos dicho anteriormente, podemos añadirlo o no.

Implementación Patrón Builder | Patrón de diseño Builder en Java
Implementación Patrón Builder
  • La clase builder declara las interfaces que vamos a definir.
  • En función de la implementación obtendremos diferentes objetos haciendo uso del mismo código.
  • El Director, marcará los paso para la construcción, es una pieza que no es imprescindible pero si recomendable.

Ejemplo de Patrón Builder

A continuación y partiendo del ejemplo que hemos comentado desde el principio sobre las diferentes configuraciones de un coche, vamos a realizar su implementación y desarrollo. Es decir, en función de las necesidades que tenga un cliente, el concesionario de venta de coches te crea un coche u otro.

Si quieres ir directamente al ejemplo hecho en Java, puedes echar un ojo en este link.

Vamos a comenzar con la clase builder, que será la encargada de definir la interfaz.

Clase Builder

package com.refactorizando.patterns.builder;

public interface Builder {

  void setCarType(CarType type);
  void setSeats(int seats);
  void setEngine(Engine engine);
  void setWheels(int wheels);
  void setLeatherSeats(Boolean leatherSeats);
  void setBatteries(int batteries);
  void setConvertible(Boolean convertible);
  void setElectricCar(Boolean electricCar);
}

La clase Builder anterior se encarga de definir los métodos que vamos a implementar en función del coche que quiera el cliente.

Definición del modelo en un Patrón Builder

A continuación vamos a realizar la definición del objeto central de nuestra aplicación, «El Coche».

package com.refactorizando.patterns.builder;

public class Car {

  private  CarType carType;
  private  Integer seats;
  private  Integer bigWheels;
  private  Engine  engine;
  private  Boolean leatherSeats;
  private  Integer batteries;
  private  Boolean convertible;
  private  Boolean electricCar;

  public Car(CarType carType, Integer seats, Integer bigWheels,
      Engine engine, Boolean leatherSeats, Integer batteries, Boolean convertible,
      Boolean electricCar) {
    this.carType = carType;
    this.seats = seats;
    this.bigWheels = bigWheels;
    this.engine = engine;
    this.leatherSeats = leatherSeats;
    this.batteries = batteries;
    this.convertible = convertible;
    this.electricCar = electricCar;
  }

  public void setBigWheels(Integer bigWheels) {
    this.bigWheels = bigWheels;
  }

  public void setEngine(Engine engine) {
    this.engine = engine;
  }

  public void setLeatherSeats(Boolean leatherSeats) {
    this.leatherSeats = leatherSeats;
  }

  public void setBatteries(Integer batteries) {
    this.batteries = batteries;
  }

  public void setConvertible(Boolean convertible) {
    this.convertible = convertible;
  }

  public void setElectricCar(Boolean electricCar) {
    this.electricCar = electricCar;
  }

  public Integer getBigWheels() {
    return bigWheels;
  }

  public Engine getEngine() {
    return engine;
  }

  public Boolean getLeatherSeats() {
    return leatherSeats;
  }

  public Integer getBatteries() {
    return batteries;
  }

  public Boolean getConvertible() {
    return convertible;
  }

  public Boolean getElectricCar() {
    return electricCar;
  }

  public CarType getCarType() {
    return carType;
  }

  public Integer getSeats() {
    return seats;
  }
}

Y a continuación definimos la potencia que tendrá el motor:

package com.refactorizando.patterns.builder;

public class Engine {

  private Integer engineCapacity;

  public Integer getEngineCapacity() {
    return engineCapacity;
  }

  public void setEngineCapacity(Integer engineCapacity) {
    this.engineCapacity = engineCapacity;
  }

  public Engine(Integer engineCapacity) {
    this.engineCapacity = engineCapacity;
  }
}

y como nos encontramos en un concesionario de venta de coches, necesitamos indicar el tipo de nuestro coche:

package com.refactorizando.patterns.builder;

public enum CarType {
  LUXURY, SPORT, BERLINA, SMALL
}

Implementación de Builder

Vamos a realizar una implementación de Builder, en este caso queremos un único producto, para ello crearemos el siguiente código:

package com.refactorizando.patterns.builder;


public class CarBuilder implements Builder {

  private  Integer seats;
  private  CarType carType;
  private  Integer bigWheels;
  private  Engine  engine;
  private  Boolean leatherSeats;
  private  Integer batteries;
  private  Boolean convertible;
  private  Boolean electricCar;

  @Override
  public void setCarType(CarType type) {
    this.carType = type;
  }

  @Override
  public void setSeats(int seats) {
    this.seats = seats;
  }

  @Override
  public void setEngine(Engine engine) {
    this.engine = engine;
  }

  @Override
  public void setWheels(int wheels) {
    this.bigWheels = wheels;
  }

  @Override
  public void setLeatherSeats(Boolean leatherSeats) {
    this.leatherSeats = leatherSeats;
  }

  @Override
  public void setBatteries(int batteries) {
    this.batteries = batteries;
  }

  @Override
  public void setConvertible(Boolean convertible) {
    this.convertible = convertible;
  }

  @Override
  public void setElectricCar(Boolean electricCar) {
    this.electricCar = electricCar;
  }

  public Car getCar() {
    return new Car(carType, seats, bigWheels, engine, leatherSeats, bigWheels, convertible, electricCar);
  }

}

Una vez hemos definido todas las piezas necesarias para la construcción de un coche, tenemos que definir un orquestador (Director) para nuestra aplicación y cree el coche que necesita el cliente.

Creación de la Clase Director

A continuación nuestro DealerShip va a crear coches de diversos tipos en función de unas características.

package com.refactorizando.patterns.builder;

public class Dealership {

  public void createLuxuryCar(Builder builder) {
    builder.setCarType(CarType.LUXURY);

    Engine engine = new Engine(2700);

    builder.setSeats(4);
    builder.setElectricCar(Boolean.TRUE);
    builder.setBatteries(2);
    builder.setConvertible(Boolean.TRUE);
    builder.setLeatherSeats(Boolean.TRUE);
    builder.setEngine(engine);

  }

  public void createSmallCar(Builder builder) {
    builder.setCarType(CarType.SMALL);

    Engine engine = new Engine(1200);
    builder.setBatteries(1);
    builder.setEngine(engine);
    builder.setSeats(4);

  }

  public void createBerlinaCar(Builder builder) {
    builder.setCarType(CarType.BERLINA);

    Engine engine = new Engine(1900);
    builder.setSeats(5);
    builder.setElectricCar(Boolean.TRUE);
    builder.setBatteries(2);
    builder.setEngine(engine);
  }

  public void createSportCar(Builder builder) {
    builder.setCarType(CarType.SPORT);

    Engine engine = new Engine(5400);
    builder.setSeats(2);
    builder.setElectricCar(Boolean.TRUE);
    builder.setBatteries(2);
    builder.setConvertible(Boolean.TRUE);
    builder.setEngine(engine);
  }

}

Ejecución de Ejemplo de Patrón Builder

Una vez hemos creado las clases anteriores es momento de ejecutar nuestro código de ejemplo, en el que indicamos que queremos un coche pequeño.

package com.refactorizando.patterns.builder;

public class Application {

  public static void main(String[] args) {

    Dealership dealership = new Dealership();

    // The client wants a simple and small car
    CarBuilder builder = new CarBuilder();
    dealership.createSmallCar(builder);

    Car car = builder.getCar();
    System.out.println("My :" + car.getCarType() + " car");

  }

}

Pros de Patrón Builder

  • Te permite crear diferentes productos en función de tus necesidades con un desacople del código. De manera que mantenemos el principio de Responsabilidad Única.
  • El código se mantiene, y si se necesita algún nuevo atributo solo se añade.

Contras de Patrón Builder

Se añade cierta complejidad en el código al tener que añadir más clases, por lo que antes de proceder a su implementación evaluar la necesidad.

Conclusión

En esta entrada sobre Patrón de diseño Builder en Java, hemos visto la construcción de un ejemplo haciendo uso del Patrón Builder. El cual nos permite mucha flexibilidad y respetar el principio de responsabilidad única, pero también puede complicar el código, por lo que antes de su desarrollo conviene su análisis.

Si quieres un ojo al ejemplo hecho en Java, puedes echar un ojo en este link.

Si necesitas más información puedes escribirnos un comentario o un correo electrónico a refactorizando.web@gmail.com o también nos puedes contactar por nuestras redes sociales Facebook o twitter y te ayudaremos encantados!


Deja una respuesta

Tu dirección de correo electrónico no será publicada.