빌더 패턴
롬복에서 자주 쓰긴 하지만, 원래 어떤 코드였고 롬복을 안쓰고 순수하게 만든다면 어떻게 되는지에 대해서 알 필요가 있다고 판단.
인텔리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;
}
}
}
엄청 길기는 길어지는데. 이것을 직접 만들게 된다면 어떤식으로 만드는지 정도는 알고 있자.
직접 만든다면
- 빌더 클래스를 Static Nested Class로 생성. 이때, 관례적으로 생성하고자 하는 클래스 이름 뒤에 Builder를 붙인다. ex) Member -> MemberBuilder
- 빌더 클래스의 생성자는 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();
}
- 옵셔널한 값들에 대해서는 각각의 속성마다 메소드로 제공하며, 이때 중요한 것은 메소드의 리턴 값이 빌더 객체 자신 이어야 한다.
// 롬복에서는 이러한 각 속성의 메서드에 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;
}
- 마지막 단계로, 빌더 클래스 내에 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;
}