빌더 패턴(Builder Pattern) 만들기 + Lombok이용
이번 주 프로젝트 과제 테스트코드가 Builder로 작성되어 있어 공부해보았습니다.
◆ Builder pattern이란?
생성 패턴 중 하나로 많은 인자를 가진 객체의 생성을 다른 객체의 도움으로 생성하는 패턴.
* 생성패턴은 인스턴스를 만드는 절차를 추상화하는 패턴이다.
User 클래스
@NoArgsConstructor
@AllArgsConstructor
public class User{
private String name;
private int age;
private int height;
private int weight;
}
객체를 만드는 대표적인 방법에는 생성자 패턴이 있다.
User user = new User("snoopy", 10, 120, 50);
User user = new User("snoopy", 10, 0, 0); // 필요없는 매개변수도 기본값으로 넣어줘야 한다.
생성자 패턴으로 객체를 생성하게 되면 인자로 어떤 값이 들어가는 지 한 눈에 알아 볼 수 없어 가독성이 떨어진다.
또한, 현재는 4개의 인자만 입력하면 되지만 인자를 많이 입력해야 한다면 순서를 맞춰 입력하고 모든 값이 입력되었는지 확인하는 과정이 아주 힘들 것이다.
두 번째 방법. 자바빈
아무런 매개변수를 받지 않는 생성자를 사용해서 인스턴스를 만들고, setter를 사용해서 필요한 필드만 설정할 수 있다.
User user = new User();
user.setName("snoopy");
user.setAge("20");
user.setHeight("120");
user.setWeight("50");
이 방법의 경우 가독성은 생성자패턴에 비해 좋다.
단점은 최종적인 인스턴스를 만들기까지 여러 번의 호출을 거쳐야 하기 때문에 중간에 사용되는 경우 안정적이지 않은 상태가 될 수 있다. 또한, setter를 사용하기 때문에 불변객체로 만들지 못한다. 코드양도 늘어난다.
생성자의 안정성과 자바빈의 가독성의 장점을 모두 취할 수 있는 대안이 빌더 패턴이다.
[ 빌더 패턴(Builder Pattern)의 장점 ]
- 필요한 데이터만 설정할 수 있음
- 유연성을 확보할 수 있음
- 가독성을 높일 수 있음
- 불변성을 확보할 수 있음( sertter 메소드가 없으므로)
위의 User 클래스를 빌더패턴으로 바꾸면 아래와 같다.
public class User{
private String name;
private int age;
private int height;
private int weight;
// 생성자를 private로 작성한 이유는
// 외부에서는 접근할 수 없고 Builder 클래스를 통해서만 객체를 생성하겠다는 의미.
private User(Builder builder) {
this.name = builder.name;
this.age = builder.age;
this.height = builder.height;
this.weight = builder.weight;
}
//Builder Class: 생성할 클래스 안에 정적 멤버 클래스로 만들어두는것이 일반적이다.
public static class Builder {
private final String name; //필수로 입력받을 값은 final 붙여줘야한다.
private final int age;
private int height;
private int weight;
//생성시 필수값 초기화.
public Builder(String name, int age) {
if (name == null || age == 0) {
throw new IllegalArgumentException("이름과 나이는 반드시 입력해야합니다.")
}
this.name = name;
this.age =age;
}
public Builder height(int height) {
this.height = height;
return this; //체이닝 할 수 있도록 자신을 return 시켜줌.
}
public Builder weight(int weight) {
this.weight = weight;
return this;
}
// 마지막에 builder() 메소드를 실행하면 this가 리턴되도록 함.
public User build() {
return new User(this);
}
}
}
Builder 사용하기
User user = User.Builder("snoopy", 12)
.height(120)
.weight(50)
.build();
User newUser = User.Builder("soda", 20)
.height(120)
.build();
값을 넣고 싶은 변수만 선택적으로 객체 생성이 가능하다.
위와 같이 builder 패턴이 좋은 것은 알겠으나 클래스를 만들 때마다 builder 클래스를 작성해야하는 번거로움이 있다.
그래서 Lombok에서 빌터 패턴을 제공한다.
@Builder 어노테이션을 사용하면 builder 클래스를 작성하지 않아도 된다.
Lombok @Builder
@Builder
public class User{
private String name;
private int age;
private int height;
private int weight;
}
//builder 사용
User user = User.builder()
.name("soda")
.age(20)
.height(170)
.weight(50)
.build();