Definition
Builder pattern is creational pattern like Factory Method or Abstract Factory design patterns.
-->The intent of the Builder design pattern is to separate the construction of a complex object from its representation. By doing so the same construction process can create different representations.
-->Builder Pattern mainly tries to solve the problems with Factory Method or Abstract Factory patterns when there are lots of attributes involved in creation of Object.
Following are the three main problem of Factory Method or Abstract Factory patterns which it tries to solve.
- Telescoping constructor anti-pattern, which arises when over a period of time there are too many constructors with different parameters.
e.g.
etc. where each addition of new attribute adds a new constructor.Pizza(int size) { ... } Pizza(int size, boolean cheese) { ... } Pizza(int size, boolean cheese, boolean pepperoni) { ... } Pizza(int size, boolean cheese, boolean pepperoni, boolean bacon) { ... }
-->Instead of using numerous constructors, the builder pattern uses another object, a builder, that receives each initialization parameter step by step and then returns the resulting constructed object at once. - There might be some attributes which are null but we would be forced to sent NULL to match the parameter list
- If the Object is heavy and creation is complex then all that complexity would be part of Factory Pattern and that could be confusing.
Builder pattern overcomes this problem by providing steps to build the object and a method which will return the final complete object at once.
-->Builder often builds a Composite Object and Often, designs start out using Factory Method (less complicated, more customizable, subclasses proliferate) and evolve towards Abstract Factory, Prototype, or Builder (more flexible, more complex) as the designer discovers where more flexibility is needed.
-->Builders are good candidates for a fluent interface.
Fluent Interface:
A fluent interface is a method for constructing object oriented APIs, where the readability of the source code is close to that of ordinary written prose.
A fluent interface is normally implemented by using method cascading also called method chaining.
Abstract Factory/Factory Method Vs Builder Pattern:
Aabstract factory pattern and the factory method pattern's intention is to enable polymorphism, while intention of the builder pattern is to find a solution to the telescoping constructor anti-pattern.
Where to use & benifits?
- Allows you to vary a product’s internal representation.
- Encapsulates code for construction and representation.
- Provides control over steps of construction process.
- Related patterns include
- Factory Pattern, which is a layer higher than a factory method.
- Template method, which defines a skeleton of an algorithm to defer some steps to subclasses or avoid subclasses
- Prototype, which creates a new object by copying an instance, so it reduces subclasses.
- Singleton, which makes a returned factory method unique
We do following steps to implement Builder design pattern:
- Make constructor of Main class private so that only nested static Builder class can create Object of it
--> To prevent creation of Object with inconsistent state. - Create a nested static class (Builder) inside main class which will have same set of attributes as main class
- Builder class should have a public constructor with all the required fields as parameters
- Builder class should have methods to set the optional fields and it should return the same Builder object after setting the optional field
- And finally it should provide a method e.g. build() which will create the final object and return to the client program
Example:
Following example is of SQL builder, here the final Object is String which is immutable so Builder Class is not supposed to have same set of attributes.
package com.meritmix.blog.designpatterns.builder;
import java.util.ArrayList;
import java.util.List;
/**
* @author Ravi Yadav
* content for MeritMix.com
* blog address: www.meritmix.com
*/
public class SqlSelect {
private String tableName = null;
private List<String> selectedColumns=new ArrayList<String>();
private String whereClaue = "";
private String groupBy = "";
public SqlSelect from(String tableName) {
this.tableName = tableName;
return this;
}
public SqlSelect column(String column) {
selectedColumns.add(column);
return this;
}
public SqlSelect where(String where) {
whereClaue =where;
return this;
}
public SqlSelect groupBy(String groupBy) {
this.groupBy = groupBy;
return this;
}
public String buildQuery() {
StringBuilder columns =new StringBuilder();
if(!selectedColumns.isEmpty()){
for (String column : selectedColumns) {
if(columns.length()> 0){
columns.append(" ,");
}
columns.append(column);
}
}else{
columns.append("*");
}
if(groupBy.length()> 0){
groupBy ="group by "+groupBy;
}
return "Select "+columns.toString()+" from "+tableName+ " where "+ whereClaue +" "+groupBy;
}
}
class SqlDemo{
public static void main(String[] args) {
String selectUserQuery = new SqlSelect().from("user").column("id").column("name").column("age")
.where("name ='Ravi'").buildQuery();
System.out.println(selectUserQuery);
//prints: Select id ,name ,age from user where name ='Ravi'
}
}
In below example, final class is Pizza and here builder class will have same set of attribute as the final class to be able to provide steps to build the final Object. And it will have a build method which will return the final Object at once.
package com.meritmix.blog.designpatterns.builder;
/**
* @author Ravi Yadav
* content for MeritMix.com
* blog address: www.meritmix.com
*/
public class Pizza {
private int size;
private boolean cheese;
private boolean pepperoni;
private boolean bacon;
public static class PizzaBuilder {
//required
private final int size;
//optional
private boolean cheese = false;
private boolean pepperoni = false;
private boolean bacon = false;
public PizzaBuilder(int size) {
this.size = size;
}
public PizzaBuilder cheese(boolean value) {
cheese = value;
return this;
}
public PizzaBuilder pepperoni(boolean value) {
pepperoni = value;
return this;
}
public PizzaBuilder bacon(boolean value) {
bacon = value;
return this;
}
public Pizza build() {
return new Pizza(this);
}
}
private Pizza(PizzaBuilder builder) {
size = builder.size;
cheese = builder.cheese;
pepperoni = builder.pepperoni;
bacon = builder.bacon;
}
}
class Demo{
public static void main(String[] args) {
Pizza pizza = new Pizza.PizzaBuilder(12)
.cheese(true)
.pepperoni(true)
.bacon(true)
.build();
}
}
No comments:
Post a Comment