빌더 패턴(Builder Pattern)은 복잡한 객체의 생성을 단순화하고, 가독성을 높이며, 불변성을 유지하는 데 유용한 디자인 패턴입니다. 이 패턴을 사용하면 객체의 속성을 단계적으로 설정할 수 있어 가독성이 좋고 유지보수가 용이합니다.
빌더 패턴이 필요한 이유
1. 생성자 오버로딩 문제 :
객체를 생성할 때 생성자 오버로딩을 활용하면 다양한 매개변수 조합을 처리할 수 있습니다. 하지만 매개변수 개수가 많아질수록 생성자 오버로딩이 복잡해지고 유지보수가 어려워집니다.
1) 생성자 오버로딩(Constructor Overloading)이란? :
클래스 내에서 같은 이름의 생성자를 여러 개 정의하는 것을 의미합니다.
즉, 매개변수의 개수나 타입이 다르게 여러 개의 생성자를 만드는 기법입니다.
생성자 오버로딩은 객체를 다양한 방법으로 초기화할 수 있어 유연성을 제공하지만,
매개변수의 개수가 많아질 경우 코드 가독성과 유지보수성이 떨어지는 문제가 발생할 수 있습니다.
public class User {
private final String name;
private final int age;
// 생성자 1: 이름만 설정 (age 기본값 0)
public User(String name) {//매개변수 name
this.name = name;
this.age = 0;
}
//필드가 많아질수록 경우의 수가 기하급수적으로 증가하여 생성자 관리가 어려워짐
//public User(String name, int age, String email, String address) { ... }
//public User(String name, int age, String email) { ... }
//public User(String name, String email) { ... }
//public User(String name, int age) { ... }
public void displayInfo() {
System.out.println("이름: " + name + ", 나이: " + age);
}
}
2. 가독성 및 유지보수
생성자의 매개변수가 많으면 어떤 값이 어떤 속성을 의미하는지 알아보기 어렵습니다.
public class Main {
public static void main(String[] args) {
//"Alice"는 이름(name)이고 25는 나이(age)이지만, 명확하게 이해하기 어렵습니다.
User user = new User("Alice", 25);
user.displayInfo(); // 출력: 이름: Alice, 나이: 25
}
}
빌더 패턴을 사용하면 아래 코드와 같이 가독성이 개선됩니다.
public static void main(String[] args) {
//setName()과 setAge()를 사용하여 어떤 값을 설정하는지 명확하게 알 수 있습니다.
User user = new User.UserBuilder()
.setName("Alice")
.setAge(25)
.build();
user.displayInfo(); // 출력: 이름: Alice, 나이: 25
}
3. 빌더패턴 적용
**빌더 패턴(Builder Pattern)**을 사용하면 생성자 오버로딩 문제를 해결할 수 있습니다.
빌더 패턴을 사용하면 유지보수가 쉬워지고, 가독성이 향상되며, 불변 객체를 만들기 용이합니다.
public class User {
// **필드 (불변 객체를 위해 final 사용)**
private final String name;
private final int age;
// **🔹 private 생성자** : 외부에서 직접 객체 생성을 막고, 빌더를 통해서만 생성할 수 있도록 제한
private User(UserBuilder builder) {
this.name = builder.name;
this.age = builder.age;
}
// **🔹 내부 정적 클래스 : UserBuilder (User 객체 생성을 위한 빌더)**
public static class UserBuilder {
private String name;
private int age;
//**🔹 setName() 메서드** : name 필드를 설정하고 현재 빌더 객체(this)를 반환하여 메서드 체이닝 가능
public UserBuilder setName(String name) {
this.name = name;
return this;
}
public UserBuilder setAge(int age) {
this.age = age;
return this;
}
// **🔹 build() 메서드** : 설정된 값으로 User 객체를 생성하여 반환
public User build() {
return new User(this);
}
}
public void displayInfo() {
System.out.println("이름: " + name + ", 나이: " + age);
}
}
Lombok의 @Builder를 사용하면 아래와 같이 객체를 더 간결하게 생성할 수 있습니다.
import lombok.Builder;
@Builder
public class User {
private final String name;
private final int age;
}
Lombok 사용을 위한 설정( Maven or Gradle) :
ㄱ. Maven (pom.xml)
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.28</version> <!-- 최신 버전 확인 -->
<scope>provided</scope>
</dependency>
ㄴ. Gradle (build.gradle)
dependencies {
compileOnly 'org.projectlombok:lombok:1.18.28'
annotationProcessor 'org.projectlombok:lombok:1.18.28'
}
결론 :
빌더 패턴을 사용하면 가독성이 향상되고 유지보수가 쉬워짐
메서드 체이닝 방식(set 메서드)을 활용하여 객체 생성을 직관적으로 처리 가능
객체의 불변성을 유지할 수 있음
빌더 패턴을 활용하면 더 유연하고 유지보수하기 좋은 코드를 작성할 수 있습니다.
'Java' 카테고리의 다른 글
| JAVA Index 기반 문자열 변형 및 랜덤 셔플러 (2) | 2025.02.15 |
|---|---|
| 비트 연산 (2) | 2025.01.31 |
| Java List.of() 객체(Apple)에 담긴 값 선택(filter)하여 꺼내기 (0) | 2025.01.27 |
| Java List.of() (1) | 2025.01.26 |
| JAVA 배열 index값 반환 메서드 (2) | 2025.01.25 |