static 팩토리 메서드와 public 생성자 모두 매개변수가 많이 필요로 한 경우에 불편한점이 있고, 객체를 생성할 때 파라미터 값을 주는데 이러한 파라미터의 값들이 무슨의미인지 잘 모르는 경우가 많고 복잡한 문제점이 생긴다.
// 필드값이 어떤 의미지??
Pet pet = new Pet(1L, "스폰지밥", "1월", "고둥길", 1D);
🔴 try 1 : 생성자
생성하고 싶은 필드들을 생성자를 사용하여 인스턴스를 만들 수 있다.
나는 이름과 주소만 받아서 생성할 꺼야!
// 필수 필드의 파라미터
public Pet(String name, String address) {
this.name = name;
this.address = address;
}
하지만 이러한 설정은 name 과 adress 만 설정이 되어 나머지 값들은 0 이 들어오거나 null 이 들어온다.
// 필수 필드만 받아 생성
Pet pet = new Pet("스폰지밥", "고둥길");
🔴 try 2 : 자바빈즈
기본 생성자를 생성하고 값의 의미에 명확성을 제공해주는 setter() 를 이용하여 값 설정을 해준다.
Pet pet = new Pet();
// setter() 사용
pet.setId(1L);
pet.setName("뚱이");
pet.setBirth("2월");
pet.setAddress("고둥길");
pet.setWeight(10);
하지만 이 방법은 setter() 를 여러번 호출 해야하고 중간까지만 설정하고 사용하는 경우가 있어 안정적이지 않는 상태에서 사용되는 단점이 있다.
또한 multi thread 환경에서 Thread safe 하지 않는 단점도 존재한다.
🔴 try 3 : 빌더
이러한 문제점을 빌더 패턴을 사용하여 문제를 해결해준다.
매개변수 중에 반드시 필요로 하는 필드와 그렇지 않은 부가적인 필드들이 있는데, 이러한 경우에 반드시 필요한 필드를 생성한 생성자에 부가적인 필드들을 추가하여 유연성을 제공하고 해당 필드의 이름도 알 수가 있어 가독성을 제공해준다.
조금의 단점?? 은 빌더 클래스를 생성하여야 하기때문에 생성자를 사용하는 것보다 코드가 많다.
public class Member {
private final Long id; // 아이디 필수
private final String name; // 이름 필수
private final String address;
private final String telephone; // 전화번호 필수
public static class Builder {
private final Long id; // 아이디 필수
private final String name; // 이름 필수
private String address;
private final String telephone; // 전화번호 필수
public Builder(Long id, String name, String telephone) {
this.id = id;
this.name = name;
this.telephone = telephone;
}
public Builder address(String address) {
this.address = address;
return this;
}
public Member build() {
return new Member(this);
}
}
public Member(Builder builder) {
this.id = builder.id;
this.name = builder.name;
this.address = builder.address;
this.telephone = builder.telephone;
}
}
빌더를 사용한 결과 가독성과 유연성을 제공해준다.
Member member = new Member.Builder(1L, "스폰지밥", "01012341234") // 필수 필드
.address("비키니시티") // 부가적인 필드
.build();
빌더 패턴은 필드의 개수가 많거나 많아질 가능성이 있을 경우에 고려해볼만 하다.
빌드 패턴을 사용하려면 빌드 클래스를 생성해야하는 번거로움이 있다.
하지만 이 기능을 지원해주는 롬복(lombok) 이라는 라이브러리가 있어 편리함을 제공해준다.
롬복(lombok) 을 사용해 빌더 패턴을 만들어보자.
@Builder // 롬복(lombok) 라이브러리의 애노테이션 사용
public class LombokMember {
private Long id = 1L;
private String name; // 이름 필수
private String address;
private String telephone; // 전화번호 필수
@Builder 애노테이션을 사용하면 클래스를 따로 만들지 않아도 사용이 가능해진다.
LombokMember member = LombokMember.builder()
.id(1L)
.name("스폰지밥")
.address("고둥길")
.telephone("01012341234")
.build();
그런데 필수로 들어가야하는 필드 값들은 어떻게 저장을 할까?
필수로 들어가야하는 값들을 저장 해주는 기능은 찾지 못했다.. 아마 없는거 같기도 한다.
대신 @Builder.Default 애노테이션이라는 기능을 찾았다.
@Builder.Default // 해당 필드의 초기 설정 값으로 빌드를 해준다
private Long id = 1L; // 초기 id 설정
private String name;
private String address;
private String telephone;
@Builder.Default 는 빌드 시에 기본 값으로 포함 하게 하는 기능이다.
위에서 초기값을 설정 해줬으니 빌드시에 설정 값이 들어간다.
LombokMember member = LombokMember.builder()
.name("스폰지밥")
.address("고둥길")
.telephone("01012341234")
.build();
롬복(lombok 관련 reference
'Book > Effective Java' 카테고리의 다른 글
[Book] ITEM 9) try-finally 대신 try-with-resource 를 사용하라 (0) | 2022.03.19 |
---|---|
[Book] ITEM 8) finalizer 와 cleaner는 피하라 (0) | 2022.03.07 |
[Book] ITEM 7) 더이상 쓰지 않는 객체 레퍼런스는 없애자 (0) | 2022.03.04 |
[Book] ITEM 6) 불필요한 객체는 만들지 말자 (0) | 2022.03.03 |
[Book] ITEM 5) 리소스를 엮을 때는 의존성 주입을 선호하라 (0) | 2022.03.03 |
[Book] ITEM 4) private 생성자로 noninstantiability를 강제할 것 (0) | 2022.03.01 |
[Book] ITEM 3) private 생성자 또는 enum 타입을 사용해서 싱글톤으로 만들것 (0) | 2022.03.01 |
[Book] ITEM 1) 생성자 대신 정적 (static) 팩토리 메서드를 고려해 볼 것 (0) | 2022.02.26 |