Builder (design pattern)
As a design pattern, the builder pattern is used to allow the creation of an array of complex objects from a source object (Product), the source object is composed of an array of parts that individually contribute to the creation of each complex object through a set of sequential calls to a specific implementation that extends the Abstract Builder class. Thus, each existing implementation of Abstract Builder will build a complex Product object in a different desired way.
The builder pattern is creational.
Often, the builder pattern builds the Composite pattern, a structural pattern.
Intent: It abstracts the process of creating a complex object, centralizing said process in a single point, in such a way that the same construction process can create different representations.
Class diagram
- Builder
- abstract class to create products.
- Concrete Builder
- implementation of the Builder
- builds and gathers the necessary parts to build the products
- Director
- builds an object, a specific product, using the Builder pattern by configuring the Builder Concrete to use.
- Output
- The complex object under construction
Advantages
• Reduces coupling.
• It allows to vary the internal representation of complex structures, respecting the common interface of the Builder class.
• The construction code of the representation is made independent. The concrete classes that handle internal representations are not part of the Builder interface.
• Each ConcreteBuilder has the specific code to create and modify a concrete internal structure.
• Different Directors with different utilities (viewers, parsers, etc) can use the same ConcreteBuilder.
• Allows greater control in the object creation process. The Director controls the creation step by step, only when the Builder has finished building the object is retrieved by the Director.
Examples
Java
*** "Product" */class Pizza { private String mass; private String salsa; private String fill fill fill; public void setMasa(String mass) { this.mass = mass; ! public void setSalsa(String salsa) { this.salsa = salsa; ! public void set(String fill fill fill) { this.fill fill fill = fill fill fill; !!♪ Abstract Builder ♪abstract class PizzaBuilder { protected Pizza pizza; public Pizza getPizza() { return pizza; ! public abstract void buildMasa(); public abstract void buildSalsa(); public abstract void buildRelleno();!♪ ConcreteBuilder ♪class HawaiPizzaBuilder extensions PizzaBuilder { public HawaiPizzaBuilder(){super.pizza = new Pizza(); public void buildMasa() { pizza.setMasa("suave"); ! public void buildSalsa() { pizza.setSalsa("sweet"); ! public void buildRelleno() { pizza.set("chorizo+alcachofas"); !!♪ ConcreteBuilder ♪class PicantePizzaBuilder extensions PizzaBuilder { public PicantePizzaBuilder(){super.pizza = new Pizza(); public void buildMasa() { pizza.setMasa("cooked"); ! public void buildSalsa() { pizza.setSalsa("picture"); ! public void buildRelleno() { pizza.set("peaker"); !!/** "Director" */class Kitchen { private PizzaBuilder pizzaBuilder; public void setPizzaBuilder(PizzaBuilder pb) { pizzaBuilder = pb; ! public Pizza getPizza() { return pizzaBuilder.getPizza(); ! public void constructPizza() { pizzaBuilder.buildMasa(); pizzaBuilder.buildSalsa(); pizzaBuilder.buildRelleno(); !!/** A customer asking for a pizza. */class BuilderExample { public static void main(String[] args) { Kitchen kitchen = new Kitchen(); PizzaBuilder hawai_pizzabuilder = new HawaiPizzaBuilder(); PizzaBuilder spicy_pizzabuilder = new PicantePizzaBuilder(); kitchen.setPizzaBuilder( hawai_pizzabuilder ); kitchen.constructPizza(); Pizza pizza = kitchen.getPizza(); !!/** * 2nd option for abstract builder perhaps more transparent for use. * Within the creation are called the build methods. * Valid as long as it is not necessary to alter * the order of the "build's" call. */abstract class OtherPizzaBuilder { protected Pizza pizza; public Pizza getPizza() { return pizza; ! public void create new() { pizza = new Pizza(); buildMasa(); buildSalsa(); buildRelleno(); ! public abstract void buildMasa(); public abstract void buildSalsa(); public abstract void buildRelleno();!/** "Director" */class Other { private OtherPizzaBuilder pizzaBuilder; public void constructPizza() { pizzaBuilder.create new(); //note that you do not need to call each build. !!
Another example of this pattern
public class BuildPattern {public void main(String args[]♪MakeAMovie makeAMovie = new MakeAMovie(new Rambo());makeAMovie.filmMovie();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*/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*/abstract class BuilderMovieStudioAbstract{Movie movie = new Movie();abstract void buildName();abstract void buildGenere();abstract void buildDuration();Movie getMovie(){return movie;!!/*** Third step: we need an idea to film that movie*/public class Rambo extensions BuilderMovieStudioAbstract{void buildDuration() {movie.setDuration(120);!void buildGenere() {movie.setGenere("Action");!void buildName() {movie.setName("Rambo");!!/*** Last Step: we make the movie*/public class MakeAMovie{private Final BuilderMovieStudioAbstract abstract;public MakeAMovie(BuilderMovieStudioAbstract abstract) {this.abstract=abstract;!public void filmMovie() {abstract.buildName();abstract.buildGenere();abstract.buildDuration();!public void seeMovie() {abstract.getMovie();!!!
Clarifications
Instance Reuse
When one sees the structure of the pattern, including the UML diagram, and especially after looking at the Kitchen class in the first Java example, one might think that the Builder pattern in turn uses the State pattern but is oriented towards object creation only but this is not, at all, essential.
It should be noted following the naming of the classes in the examples, that the Concrete Builder elements of the first option of the first example (HawaiPizzaBuilder and PicantePizzaBuilder) and the Director element (MakeAMovie) of the second example should only be used once and discarded since any other subsequent attempt to reuse them by calling the Director's build method would be getting the old Product again and not a new instance. Thus, it must be instantiated every time you want to build a new Product, either the Concrete Builder or the Director respectively.
This does not happen with the second option of the first example, since the Builder element returns a new instance each time it is called by the Director's build method and, thus, it can be said that it satisfies the State pattern and that its use it may generate fewer errors although the other options are still perfectly valid. The only objection is that this second option is still not thread-safe, none of them are; If we wanted to provide this concept in an easy way, we can use thread-local storage or make the methods of each Concrete Builder receive the specific product to be modified as an argument.
Builder Terminology
In recent years, Builder terminology has been extended to the concept of auto-generation, or manually, of code in classes, where Setters methods are added, one for each attribute of the class and with a name equal to the variable, where in addition to configuring the value, they return the actual instance of the object, allowing the chaining of successive calls so that the values required in the instance can be provided in a compact, declarative and readable way. Furthermore, you can even provide a Builder method on the class that builds the entire class. Although this is a good methodology to generate clean code, it should not be confused with the defined pattern, since it can easily be checked that it does not provide the necessary elements of the class diagram, nor, therefore, with the necessary collaborations between them.
Although it is true that a not too strict implementation of the Builder design pattern could make use of this methodology internally.
Contenido relacionado
Minesweeper
Annex: XML dialects
Roaming