빌더 패턴 (Builder Pattern)
빌더 패턴은 객체의 생성과 표현을 분리하여 복잡한 객체를 단순화하는 디자인 패턴 중 하나이다. 주로 매개변수가 많은 생성자나 정적 팩토리 메서드의 대안으로 사용되며, 가독성이 높아지고 객체의 필드 추가나 변경이 용이해진다.
public class Person {
private final String firstName;
private final String lastName;
private final int age;
private final String address;
private Person(Builder builder) {
this.firstName = builder.firstName;
this.lastName = builder.lastName;
this.age = builder.age;
this.address = builder.address;
}
public static class Builder {
private final String firstName;
private final String lastName;
private int age;
private String address;
public Builder(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
public Builder age(int age) {
this.age = age;
return this;
}
public Builder address(String address) {
this.address = address;
return this;
}
public Person build() {
return new Person(this);
}
}
// Getters...
}
사용 예시:
Person person = new Person.Builder("John", "Doe")
.age(30)
.address("123 Main St")
.build();
빌더 클래스가 static inner class로 구현되는 이유
하나의 빌더 클래스는 하나의 대상 객체 생성만을 위해 사용된다. 그래서 두 클래스를 물리적으로 그룹핑함으로써 두 클래스간의 관계에 대한 파악을 쉽게 할 수 있다.
대상 객체는 오로지 빌더 객체에 의해 초기화 된다. 즉, 생성자를 외부에 노출시키면 안되기 때문에 생성자를 private로 하고, 내부 빌더 클래스에서 private 생성자를 호출함으로써 오로지 빌더 객체에 의해 초기화 되도록 설계 할 수 있다.
inner class를 쓰면 좋은건 알겠는데 왜 하필 static 으로 선언해주어야 하냐면, 정적 내부 클래스는 외부 클래스의 인스턴스 없이도 생성할 수 있는데, 만일 일반 내부 클래스로 구성한다면 내부 클래스를 생성하기도 전에 외부 클래스를 인스턴스화 해야 한다. 빌더가 최종적으로 생성할 클래스의 인스턴스를 먼저 생성해야 한다면 모순이 생기기 때문이다.
메모리 누수 문제 때문에 static으로 내부 클래스를 정의해주어야 한다.
출처: https://inpa.tistory.com/entry/GOF-💠-빌더Builder-패턴-끝판왕-정리#thankYou
스프링에서는 Lombok이나 스프링의 @Builder 애노테이션을 활용하여 빌더 패턴을 구현할 수 있다.
import lombok.Builder;
import lombok.Data;
@Data
@Builder
public class Person {
private String firstName;
private String lastName;
private int age;
private String address;
}
@Builder 애노테이션 사용 예시:import lombok.Builder;
import org.springframework.stereotype.Component;
@Component
public class Person {
private String firstName;
private String lastName;
private int age;
private String address;
@Builder
public Person(String firstName, String lastName, int age, String address) {
this.firstName = firstName;
this.lastName = lastName;
this.age = age;
this.address = address;
}
// Getters and Setters...
}
사용 예시:
Person person = Person.builder()
.firstName("John")
.lastName("Doe")
.age(30)
.address("123 Main St")
.build();
빌더 패턴은 객체의 생성 및 설정이 복잡한 경우에 특히 유용하고, 가독성과 유지보수성을 높여준다.