
빌더 패턴은 복잡한 객체를 생성하는 방법을 정의하는 디자인 패턴으로,
일반적으로 객체 생성과 객체 표현을 분리하는 목적으로 사용된다.즉, 동일한 생성 절차를 통해 서로 다른 표현 결과를 만들 수 있다.
생성할 객체의 각 부분을 생성하고 조립하는 방법을 정의하는 인터페이스
빌더 인터페이스의 메서드를 사용하여 객체를 생성하는 절차를 정의
생성자 인자가 많을 때 유용인자가 많을 경우, 그 순서를 정확히 기억하기 어려워지는데 빌더 패턴을 사용하면 이를 해결할 수 있다.
코드의 가독성과 재사용성코드의 가독성과 재사용성을 향상시킬 수 있다.
객체 불변성객체를 불변(Immutable)하게 만들 수 있다.
코드 복잡성 증가빌더 패턴을 사용하면 클래스 코드가 늘어나고, 복잡해질 수 있다.
간단한 객체에 대해 빌더 패턴을 사용하면 과도한 설계로 이어질 수 있다.
빌더 생성 비용각 객체를 생성할 때마다 빌더를 생성해야 한다.
따라서 객체가 많이 필요한 경우 빌더 패턴을 사용하면 성능 저하가 일어날 수 있다.
유지보수성 감소만약 객체의 필드가 수정되면 해당 빌더 클래스도 함께 수정해야 한다.
이는 유지보수 비용을 증가시킬 수 있다.
이러한 단점으로 인해,
빌더 패턴은 객체 생성이 복잡하거나 선택적 인자가 많을 때 주로 사용된다.
그 외의 경우, 일반적인 생성자나 팩토리 메소드를 사용하는 것이 더 간단하고 효율적일 수 있다.
아래 코드에서 User는 복잡한 객체이다.
아래의 코드에서 User 객체는 선택적인 필드가 많기 때문에,
객체를 생성할 때 매개변수를 모두 명시해야 한다.
public class User {
// 필수 인자
private final String firstName;
private final String lastName;
// 선택적 인자
private int age;
private String phone;
private String address;
public User(String firstName, String lastName, int age, String phone, String address) {
this.firstName = firstName;
this.lastName = lastName;
this.age = age;
this.phone = phone;
this.address = address;
}
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
public int getAge() {
return age;
}
public String getPhone() {
return phone;
}
public String getAddress() {
return address;
}
}
User user = new User("First", "Last", 30, "12345678", "Fake address 1234");
System.out.println(user.getFirstName()); // Output: First
System.out.println(user.getLastName()); // Output: Last
System.out.println(user.getAge()); // Output: 30
System.out.println(user.getPhone()); // Output: 12345678
System.out.println(user.getAddress()); // Output: Fake address 1234
이 코드는 복잡하고 가독성이 떨어진다.
필드가 많아지면 매개변수의 순서를 헷갈릴 수도 있다.
선택적인 필드가 많아지면 오버로딩된 생성자를 여러 개 만들어야 하는 문제도 생긴다.이렇게 복잡한 객체를 만들 때 빌더 패턴을 사용하면 코드의 가독성을 높이고, 오류를 줄일 수 있다.
UserBuilder는 빌더 역할을 하며, 각 setter 메서드는 빌더 객체 자신을 반환하므로
메서드 체이닝이 가능하다.
public class User {
// 필수 인자
private final String firstName;
private final String lastName;
// 선택적 인자
private int age;
private String phone;
private String address;
private User(UserBuilder builder) {
this.firstName = builder.firstName;
this.lastName = builder.lastName;
this.age = builder.age;
this.phone = builder.phone;
this.address = builder.address;
}
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
public int getAge() {
return age;
}
public String getPhone() {
return phone;
}
public String getAddress() {
return address;
}
public static class UserBuilder {
private final String firstName;
private final String lastName;
private int age;
private String phone;
private String address;
public UserBuilder(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
public UserBuilder age(int age) {
this.age = age;
return this;
}
public UserBuilder phone(String phone) {
this.phone = phone;
return this;
}
public UserBuilder address(String address) {
this.address = address;
return this;
}
public User build() {
return new User(this);
}
}
}
User user = new User.UserBuilder("First", "Last")
.age(30)
.phone("12345678")
.address("Fake address 1234")
.build();
System.out.println(user.getFirstName()); // Output: First
System.out.println(user.getLastName()); // Output: Last
System.out.println(user.getAge()); // Output: 30
System.out.println(user.getPhone()); // Output: 12345678
System.out.println(user.getAddress()); // Output: Fake address 1234