Creational_Builder Pattern
π€·π»ββοΈ What would happen if we did not have builder?
- Imagine we have a
tripclass - attributes such as
place,how many nights,how many days,hotel,start date⦠- when we create a trip,
we have some requirements
- β οΈ
how many daysshould behow many nights+ 1 - β οΈ for a one-day trip, we do not want to include
how many nights,how many days,hotel π maybe we can use several constructors?
- ππ» When creation of an instance is complicated
- condition among attributes,
- several constructors needed
- we can use a
builder patternto facilitate the creation of an instance
β Diagram
ππ» Before builder
- tour plan has many attributes
1
2
3
4
5
6
7
8
public class TourPlan {
private String title;
private int nights;
private int days;
private LocalDate startDate;
private String whereToStay;
private List<DetailPlan> plans;
}
- In main class
1
2
3
4
5
6
7
8
9
10
11
//for several day trip, need to set several attributes
TourPlan longTripPlan = new TourPlan("Spain", 3, 4, "hotel"...);
longTripPlan.setTitle("Spain");
longTripPlan.setNights(3);
longTripPlan.setDays(4); //day should always be night + 1
// ππ» how can I set conditions among attributes
// when creating instance?
//for one day trip, I only want to set name
// ππ» need several constructors with different parameters
TourPlan onedayPlan = new TourPlan("beach");
ππ» After implementing builder pattern
βοΈ Builder class
- methods return the
builder classitself, - so later method chaining is possible
- look at
App
1
2
3
4
5
6
7
8
9
10
11
12
public interface TourPlanBuilder {
//methods return itself, λ΄κ° λ΄ μμ μ returnν¨μΌλ‘μ¨ λ΄ μμ μ λ©μλ λ λΆλ₯΄κΈ° κ°λ₯
TourPlanBuilder title(String title);
TourPlanBuilder nightsAndDays(int nights, int days);
TourPlanBuilder startDate(LocalDate localDate);
TourPlanBuilder whereToStay(String whereToStay);
TourPlanBuilder addPlan(int day, String plan);
//last, return Plan
TourPlan getPlan(); //and finally return the plan
}
βοΈ Concrete Builder class
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class DefaultTourBuilder implements TourPlanBuilder{
private String title;
private int nights;
private int days;
private LocalDate startDate;
private String whereToStay;
private List<DetailPlan> plans;
@Override
public TourPlanBuilder title(String title) {
this.title = title;
return this;
}
//override all methods
@Override
public TourPlan getPlan() {
return new TourPlan(title, nights, days, startDate, whereToStay, plans); //return Plan
}
}
βοΈ Main class
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class App {
public static void main(String[] args) {
TourPlanBuilder builder = new DefaultTourBuilder();
// ππ» without creating many constructors, can call methods I want from builder class
TourPlan shortPlan = builder.title("beach")
.startDate(LocalDate.of(2020, 10, 10))
.getPlan();
TourPlan longPlan = builder.title("Spain")
.nightsAndDays(4, 5)
.whereToStay("hotel")
.startDate(LocalDate.of(2020, 10, 10))
.addPlan(0, "madrid")
.addPlan(1, "barcelona")
.addPlan(2, "sevilla")
.addPlan(3, "toledo")
.getPlan();
}
βοΈ Director class
- if instance is created in the same way several times,
- create director class
- can hide how to make the instance
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class Director {
private TourPlanBuilder tourPlanBuilder;
public Director(TourPlanBuilder tourPlanBuilder) {
this.tourPlanBuilder = tourPlanBuilder;
}
//when I want to set everything for the plan
public TourPlan SpainPlan(){
return tourPlanBuilder.title("Spain")
.nightsAndDays(4, 5)
.whereToStay("hotel")
.startDate(LocalDate.of(2020, 10, 10))
.addPlan(0, "madrid")
.addPlan(1, "barcelona")
.addPlan(2, "sevilla")
.addPlan(3, "toledo")
.getPlan();
}
//when I want to only set title and startDate for plan
public TourPlan shortPlan(){
return tourPlanBuilder.title("beach")
.startDate(LocalDate.of(2020, 10, 10))
.getPlan();
}
}
βοΈ Main class
1
2
3
4
5
6
public class App {
public static void main(String[] args) {
Director director = new Director(builder);
TourPlan shortPlan1 = director.shortPlan();
TourPlan longPlan2 = director.SpainPlan();
}
β Minimum code
- in
TourPlanBuilder interfaceadd methodnewInstance()1 2 3
public interface TourPlanBuilder { TourPlanBuilder newInstance(); }
- do not have to re-write all the attributes in
DefaultTourBuilder
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class DefaultTourBuilder implements TourPlanBuilder{
private TourPlan tourplan; //now do not need all fields
@Override
public TourPlanBuilder newInstance() { //but need to initiate new instance
this.tourplan = new TourPlan();
return this;
}
@Override
public TourPlanBuilder title(String title) {
this.tourplan.setTitle(title);
return this;
}
}
ππ»
- can create difficult instances easily
- can put orders in creating instances
- can put conditions in creating instances
- do not need so many constructors for all different cases
π οΈ
- StringBuilder(
not synchronized) can use
append()to keep adding String- Stream.builder()
can use
add()- annotation
@Builder creates builder for that class
UriComponentsBuilder- has methods such as
scheme(),host()
This post is licensed under CC BY 4.0 by the author.
