Builder (patrón de diseño)
Como
Patrón de diseño, el patrón builder (Constructor) es usado para permitir la
creación de una variedad de objetos complejos desde un objeto fuente
(Producto), el objeto fuente se compone de una variedad de partes que
contribuyen individualmente a la creación de cada objeto complejo a través de
un conjunto de llamadas a interfaces comunes de la clase Abstract Builder.
A
menudo, el patrón builder construye el patrón Composite, un patrón estructural.
Intención:
Abstrae el proceso de creación de un objeto complejo, centralizando dicho
proceso en un único punto, de tal forma que el mismo proceso de construcción
pueda crear representaciones diferentes.
Diagrama de Clases
Builder:
interfaz abstracta para crear productos.
Concrete
Builder: implementación del Builder construye y reúne las partes necesarias
para construir los productos
Director:
construye un objeto usando el patrón Builder
Producto:
El objeto complejo bajo construcción
Ventajas
•
Reduce el acoplamiento.
•
Permite variar la representación interna de estructuras compleja, respetando la
interfaz común de la clase Builder.
• Se
independiza el código de construcción de la representación. Las clases
concretas que tratan las representaciones internas no forman parte de la
interfaz del Builder.
•
Cada ConcreteBuilder tiene el código especifico para crear y modificar una
estructura interna concreta.
•
Distintos Director con distintas utilidades (visores, parsers, etc) pueden
utilizar el mismo ConcreteBuilder.
•
Permite un mayor control en el proceso de creación del objeto. El Director
controla la creación paso a paso, solo cuando el Builder ha terminado de
construir el objeto lo recupera el Director.
Ejemplos
Java
/** "Producto" */ class Pizza { private String masa = ""; private String salsa = ""; private String relleno = ""; public void setMasa(String masa) { this.masa = masa; } public void setSalsa(String salsa) { this.salsa = salsa; } public void setRelleno(String relleno) { this.relleno = relleno; } } /** "Abstract Builder" */ abstract class PizzaBuilder { protected Pizza pizza; public Pizza getPizza() { return pizza; } public void crearNuevaPizza() { pizza = new Pizza(); } public abstract void buildMasa(); public abstract void buildSalsa(); public abstract void buildRelleno(); } /** "ConcreteBuilder" */ class HawaiPizzaBuilder extends PizzaBuilder { public void buildMasa() { pizza.setMasa("suave"); } public void buildSalsa() { pizza.setSalsa("dulce"); } public void buildRelleno() { pizza.setRelleno("chorizo+alcachofas"); } } /** "ConcreteBuilder" */ class PicantePizzaBuilder extends PizzaBuilder { public void buildMasa() { pizza.setMasa("cocida"); } public void buildSalsa() { pizza.setSalsa("picante"); } public void buildRelleno() { pizza.setRelleno("pimienta+salchichón"); } } /** "Director" */ class Cocina { private PizzaBuilder pizzaBuilder; public void setPizzaBuilder(PizzaBuilder pb) { pizzaBuilder = pb; } public Pizza getPizza() { return pizzaBuilder.getPizza(); } public void construirPizza() { pizzaBuilder.crearNuevaPizza(); pizzaBuilder.buildMasa(); pizzaBuilder.buildSalsa(); pizzaBuilder.buildRelleno(); } } /** Un cliente pidiendo una pizza. */ class BuilderExample { public static void main(String[] args) { Cocina cocina = new Cocina(); PizzaBuilder hawai_pizzabuilder = new HawaiPizzaBuilder(); PizzaBuilder picante_pizzabuilder = new PicantePizzaBuilder(); cocina.setPizzaBuilder( hawai_pizzabuilder ); cocina.construirPizza(); Pizza pizza = cocina.getPizza(); } } /** * Dejo una 2da opción para el abstract builder. * Creo que es más transparente para su uso. * Dentro del crear se llaman los métodos build. * Es válido siempre y cuando no se necesite alterar * el orden del llamado a los "build's". * * @author Ber */ abstract class OtroPizzaBuilder { protected Pizza pizza; public Pizza getPizza() { return pizza; } public void crearNuevaPizza() { pizza = new Pizza(); buildMasa(); buildSalsa(); buildRelleno(); } public abstract void buildMasa(); public abstract void buildSalsa(); public abstract void buildRelleno(); } /** "Director" */ class OtraCocina { private OtroPizzaBuilder pizzaBuilder; public void setPizzaBuilder(OtroPizzaBuilder pb) { pizzaBuilder = pb; } public Pizza getPizza() { return pizzaBuilder.getPizza(); } public void construirPizza() { pizzaBuilder.crearNuevaPizza(); //notar que no se necesita llamar a cada build. } }
Otro ejemplo:
public class BuildPattern { public void main(String args[]){ MakeAMovie makeAMovie = new MakeAMovie(new Rambo()); MakeAMovie.filmAMovie(); Movie movie = makeAMovie.seeMovie(); System.out.println(movie.genere); System.out.println(movie.name); System.out.println(movie.duration); } /** * first step we need the movie * @author Pperez * */ public class Movie{ public String name = ""; public String genere = ""; public int duration; public void setName(String name){ this.name=name; } public void setGenere(String genere){ this.genere=genere; } public void setDuration(int duration){ this.duration=duration; } } /** * Second step we need a studio to make the movie * @author Pperez * */ abstract class BuilderMovieStudioAbstract{ Movie movie; abstract void buildName(); abstract void buildGenere(); abstract void buildDuration(); Movie getMovie(){return movie;} } /** * third step we need an idea to film that movie * @author Pperez * */ public class Rambo extends BuilderMovieStudioAbstract{ void buildDuration() { movie.setDuration(120); } void buildGenere() { movie.setGenere("Action"); } void buildName() { movie.setName("Rambo"); } } /** * Last Step we make the movie. * @author Pperez * */ public class MakeAMovie{ BuilderMovieStudioAbstract abstractMovie; public MakeAMovie(BuilderMovieStudioAbstract abstractMovie) { this.abstractMovie=abstractMovie; } public void filmAMovie(){ abstractMovie.buildDuration(); abstractMovie.buildName(); abstractMovie.buildGenere(); } public Movie seeMovie(){ return abstractMovie.getMovie(); } } }
No hay comentarios:
Publicar un comentario