본문으로 건너뛰기

빌더 패턴


롬복에서 자주 쓰긴 하지만, 원래 어떤 코드였고 롬복을 안쓰고 순수하게 만든다면 어떻게 되는지에 대해서 알 필요가 있다고 판단.

인텔리J에서 제너레이트를 했을 때

이러한 코드를 InteliJ에서 Builder제너레이터를 사용하면

public class Employee {

private Long id;

private String name;

private Integer age;

}

이렇게 된다.
제너레이터를 사용할때는 inner builder 에 체크를 했고, 모든 필드를 선택했다.

public class Employee {

private Long id;

private String name;

private Integer age;

public static final class EmployeeBuilder {
private Long id;
private String name;
private Integer age;

private EmployeeBuilder() {
}

public static EmployeeBuilder anEmployee() {
return new EmployeeBuilder();
}

public EmployeeBuilder withId(Long id) {
this.id = id;
return this;
}

public EmployeeBuilder withName(String name) {
this.name = name;
return this;
}

public EmployeeBuilder withAge(Integer age) {
this.age = age;
return this;
}

public Employee build() {
Employee employee = new Employee();
employee.id = this.id;
employee.name = this.name;
employee.age = this.age;
return employee;
}
}
}

엄청 길기는 길어지는데. 이것을 직접 만들게 된다면 어떤식으로 만드는지 정도는 알고 있자.


직접 만든다면

  1. 빌더 클래스를 Static Nested Class로 생성. 이때, 관례적으로 생성하고자 하는 클래스 이름 뒤에 Builder를 붙인다. ex) Member -> MemberBuilder
  2. 빌더 클래스의 생성자는 private으로 하며, 필수 값들에 대해 생성자의 파라미터로 받는다.

생성자를 private으로 해놨기 때문에, 직접 생성이 불가능하고 builder라는메서드(여기서는 anEmployee라는 메서드)를 통해서만 객체 생성이 가능하게 된다.

public static final class EmployeeBuilder {
private Long id;
private String name;
private Integer age;

// private 기본생성자
private EmployeeBuilder() {
}

// 팩토리 메서드 패턴과 같다. 롬복에서는 이부분이 builder이라는 메서드명으로 되어있다.
public static EmployeeBuilder anEmployee() {
return new EmployeeBuilder();
}
  1. 옵셔널한 값들에 대해서는 각각의 속성마다 메소드로 제공하며, 이때 중요한 것은 메소드의 리턴 값이 빌더 객체 자신 이어야 한다.
        // 롬복에서는 이러한 각 속성의 메서드에 with키워드가 없다.  
public EmployeeBuilder withId(Long id) {
this.id = id;
return this;
}

// 롬복에서는 이러한 각 속성의 메서드에 with키워드가 없다.
public EmployeeBuilder withName(String name) {
this.name = name;
return this;
}

// 롬복에서는 이러한 각 속성의 메서드에 with키워드가 없다.
public EmployeeBuilder withAge(Integer age) {
this.age = age;
return this;
}
  1. 마지막 단계로, 빌더 클래스 내에 build() 메소드를 정의하여 클라이언트 프로그램에게 최종 생성된 결과물을 제공한다.
    이렇듯 build()를 통해서만 객체 생성을 제공하기 때문에 생성 대상이 되는 클래스의 생성자는 private으로 정의해야 한다.
        // 생성자가 private 라는것에 주목
private EmployeeBuilder() {
}

//.
//.
//.
//.
//.

public Employee build() {
Employee employee = new Employee();
employee.id = this.id;
employee.name = this.name;
employee.age = this.age;
return employee;
}