개발지식 먹는 하마 님의 블로그
[내일배움캠프 24일차] _ Builder Pattern로 코드 품질 향상 + 가변 인자 본문
챌린지반 코드 리팩토링 시간을 통해 키오스크 과제를 다른 사람들은 어떻게 해결했는지를 알 수 있었다.
해당 코드들이 어떤 면에서 클린하고 좋은 코드인지를 알 수 있어 굉장히 유익했다.
그중에서도 가장 기억에 남는 부분은 빌더 패턴과 유사한 방법의 MenuItem 생성 코드였다.
List<Menu> menu = Arrays.asList(
new Menu("햄버거").addMenuItems(
//햄버거 메뉴들...
),
new Menu("음료").addMenuItems(
//음료 메뉴들...
),
new Menu("사이드").addMenuItems(
//음료 메뉴들...
)
);
//출처 : withong님 github 코드
📌 Builder Pattern
객체 생성 시 생성자의 인자가 많을 때 가독성을 높이고, 객체의 불변성을 유지할 수 있도록 도와주는 디자인 패턴
✅ 가독성 향상: 메서드 체이닝을 활용하여 명확하고 직관적인 객체 생성
✅ 불변성 유지: final 필드를 사용하여 객체를 변경할 수 없도록 설정 가능
✅ 유지보수 용이: 생성자 오버로딩을 줄이고, 선택적 매개변수를 쉽게 추가 가능
✅ 코드의 안정성: 인자의 순서를 실수로 바꿔도 컴파일 타임에서 에러 감지 가능
✏️ 생성자 오버로딩의 한계
public class User {
private String name;
private int age;
private String email;
private String address;
public User(String name, int age) {
this.name = name;
this.age = age;
}
public User(String name, int age, String email) {
this.name = name;
this.age = age;
this.email = email;
}
//생성자의 매개변수가 많아질수록 늘어나는 생성자...
}
- 생성자의 매개변수가 많아질수록, 변수 개수에 따라 오버로딩을 계속 추가해야 하는 문제가 발생한다.
이름만 받는 생성자
나이만 받는 생성자
이메일 주소만 받는 생성자
이름과 나이만 받는 생성자 등... - 인자의 순서를 잘못 입력할 가능성도 높아진다.
(이름이 먼저였나? 나이가 먼저였나?)
빌더 패턴을 사용하면 불필요한 오버로딩을 제거할 수 있다.
public class User {
private final String name;
private final int age;
private final String email;
private final String address;
//private 생성자 (Builder만 객체를 생성할 수 있도록 설정)
private User(Builder builder) {
this.name = builder.name;
this.age = builder.age;
this.email = builder.email;
this.address = builder.address;
}
//Builder 클래스 (User의 내부 정적 클래스)
public static class Builder {
private String name;
private int age;
private String email;
private String address;
public Builder(String name, int age) { // 필수 매개변수
this.name = name;
this.age = age;
}
public Builder email(String email) { // 선택적 매개변수
this.email = email;
return this;
}
public Builder address(String address) {
this.address = address;
return this;
}
public User build() { // 최종 객체 생성
return new User(this);
}
}
}
위와 같이 빌더를 따로 생성하고 이를 이용해 아래와 같이 메서드 체이닝을 활용해 객체를 생성하게 되면,
Stream을 사용할 때와 유사한 형태로 코드가 작성되며
원하는 매개변수만 선택적으로 설정할 수 있다.
이때, 메서드 체이닝을 사용하려면 빌더의 각 메서드가 this를 반환해야 한다.
public class Main {
public static void main(String[] args) {
// 빌더 패턴을 사용하여 User 객체 생성
User user = new User.Builder("John Doe", 25)
.email("john@example.com")
.address("New York")
.build();
}
}
📌 4. 빌더 패턴 vs 생성자 vs Setter
방식 | 빌더 패턴 | Setter | 생성자 |
가독성 | 매우 높음⭐⭐⭐⭐⭐ | 높음⭐⭐⭐ | 낮음⭐ |
불변성 유지 | 가능✔️ | 불가능❌ | 가능✔️ |
확장성 | 매우 높음⭐⭐⭐⭐⭐ | 높음⭐⭐⭐ | 낮음⭐ |
매개변수 선택 | 가능✔️ | 가능✔️ | 불가능❌ |
생성자, Setter와 성능을 비교했을 때 안 쓸 이유가 없어보이는 성능이다.
빌더 패턴과 유사하게 Menu를 생성할 때 MenuItem을 가변인자를 사용해 추가하는 방식도 인상적이었다.
public Menu addMenuItems(MenuItem... menu) {
// 전달된 menu를 리스트로 변환하여 menuItems 리스트에 추가
this.menuItems.addAll(Arrays.asList(menu));
// 현재 Menu 객체 반환
return this;
}
//출처 : withong님 github 코드
📌 가변 인자 Varargs
메서드의 매개변수 개수를 가변적으로 받을 수 있도록 지원하는 기능이다.
배열을 사용하지 않고도 여러 개의 인자를 넘길 수 있다.
✅ 내부 동작
가변 인자는 내부적으로 배열로 변환된다.
따라서, 실제로는 매개변수 타입 배열을 선언한 것과 동일한 의미이다.
public void printNumbers(int... numbers) { } // 가변 인자
public void printNumbers(int[] numbers) { } // 배열로 직접 선언
✅ 가변인자 사용법
매우 간단하다!
메서드의 매개변수 타입 뒤에 세 개의 점 ...을 붙여서 사용한다.
public void 메서드명(매개변수 타입... 변수명)
가변 인자를 사용할 때, 가변 인자만 매개변수로 받을 수 있는 것은 아니다.
일반 매개변수도 함께 사용 가능하다.
public void 메서드명(일반 매개변수1, 일반 매개변수2, 매개변수 타입... 변수명)
- 단, 맨 마지막에 위치해야 한다.
- 가변인자는 한 메서드에 한 번만 사용할 수 있다.
- 오버로딩 시, 오류가 발생할 가능성이 있다.
public void printNumbers(int... numbers) { }
public void printNumbers(int num) { } // 가변 인자와 혼동될 수 있어 오류 발생 가능
✅ 오버로딩 발생 시, 해결 방법
- 다른 타입의 매개변수를 추가해 명확하게 구분한다.
- 가변 인자 대신 명시적으로 배열을 선언한다.
- 메서드 이름을 다르게 설정한다.
'내일배움캠프 (CS25)' 카테고리의 다른 글
[내일배움캠프 29일차] _ Spring 유효성 검사 (0) | 2025.03.28 |
---|---|
[내일배움캠프 27일차] _ 스케줄러 구현 및 트러블 슈팅 (0) | 2025.03.26 |
[내일배움캠프 23일차] _ 키오스크 프로젝트 피드백 (0) | 2025.03.20 |
[내일배움캠프 19일차] _ 키오스크 구현, 트러블 슈팅 (0) | 2025.03.14 |
[내일배움캠프 17일차] _ 거리두기 확인하기 문제 풀이 (0) | 2025.03.12 |