Post

Creational_Builder Pattern

πŸ€·πŸ»β€β™€οΈ What would happen if we did not have builder?

  • Imagine we have a trip class
  • attributes such as place, how many nights, how many days, hotel, start date…
  • when we create a trip,
  • we have some requirements

  • ⚠️ how many days should be how 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 pattern to facilitate the creation of an instance

βœ… Diagram

Screenshot-2026-02-28-at-18-51-48.png

πŸ‘ŽπŸ» 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 class itself,
  • 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 interface add method newInstance()
    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.