@Builder 와 Modelmapper - (1) @Builder

HelloWorld·2023년 2월 5일
1

주로 엔티티와 DTO간의 데이터 전달에서, 빌더 모델매퍼와 같은 방식이 있다는 것은 알고 있었지만 정확한 개념이나 사용방법을 잘 익히지 못하고 있었기에 사용을 미루고 있었다. 제일 기본적인

public void toEntity(Member member) {
	this.memberName = member.getMemberName();
    this.memberPhone = member.getMemberPhone();
}

과 같은 방식으로 데이터를 주고 받았었다.

프로젝트 상에서 큰 문제를 일으키지 않았고, 잘 작동했기 때문에 이를 바꾸려고 하지는 않았었다. 그러나 엔티티의 컬럼들이 많아지고 넣어야 하는 테이터들이 증가하자 이렇게 사용하기에는 귀찮고 더 편한 방법을 찾기 시작했다.

그렇게 찾게된게 1. @Builder 2. Modelmapper 이다. 각각의 장단점과 사용방법에 대해 알아보려 한다.

1. @Builder

빌더패턴에는 1. 점증적 생성자 패턴 2. 자바 빈즈 패턴 3. 빌더 패턴이 있다. 1번과 2번의 경우 코드량도 많고 가독성이 그렇게 좋지 않기 때문에 생략하도록 하겠다.
** 자바 빈즈 패턴
뒤에 잠깐 언급이 나와 설명하자면,

public class Member {
	private String name;
    private int age;
    
    public Member() {}
    
    public void setName(String name) {
    	this.name = name;
   	}
    
    public void setAge(int age) {
    	this.age = age;
    }
}
Member member = new Member(); // 선 객체 생성, 후 값 부여
member.setName("ABC");
member.setAge(22);

1-1. 빌더 패턴의 장점

생성자에 매개변수가 많을 경우 빌더를 고려하면 좋다. 정보들은 자바빈즈패턴처럼 받지만, 데이터 일관성을 위해 정보들을 다 받은 후에 객체를 생성한다.

  • 불필요한 생성자 제거
  • 데이터의 순서에 상관없이 객체 생성 가능
  • setter 메서드가 없으므로 변경 불가능한 객체 만들수 있음
  • build() 함수가 null인지 체크해주기 때문에 검증 가능

1-2. 빌더 패턴 사용 방법(1)

빌더 클래스를 직접 만드는 방법도 있지만 이것은 스킵...
롬복을 이용해서 사용하는 방법은 다음과 같다.

@Builder
public class Member{
	private final String name;
    private final int age;
}
Member member = Member.builder()
	.name("ABC")
    .age(22)
    .build();

간단하게 생성이 가능하다.

1-3. 빌터 패던 사용 방법(2)

우리가 엔티티에 빌더를 바로 적용해서 원하는 값을 넣을 수 있지만, RequestDto나 다른 Dto를 통해 값을 얻어올 경우 엔티티의 컬럼과 정확하게 일치하지 않을 경우가 많다. 이 경우의 빌더 사용법을 보자.

  1. 빌더를 사용하지 않을 경우

** RequestDto에서 name, age만 받아온다는 가정
Entity

public class Member {
	private String name;
    private int age;
    private String house;
    
    public void toEntity(RequestDto requestDto, String house) {
    	this.name = requestDto.getName();
        this.age = requestDto.getAge();
        this.house = house;
    }
}
@Service
@RequiredArgsConstructor
public class MemberService {

	private final MemberRepository memberRepository;
	
    @Trnasactional
    public void saveMember(RequestDto requestDto, String house) {
    
    	Member member = new Member();
        member.toEntity(requestDto, house);
        memberRepository.save(member);
    }
}
  1. 빌더를 사용할 경우
public class Member {
	private String name;
    private int age;
    private String house;
    
    @Builder
    public Member(RequestDto requestDto, String house) {
    	this.name = requestDto.getName();
        this.age = requestDto.getAge();
        this.house = house;
    }
}
@Service
@RequiredArgsConstructor
public class MemberService {

	private final MemberRepository memberRepository;
	
    @Trnasactional
    public void saveMember(RequestDto requestDto, String house) {
    
    	Member member = Member.builder()
        	.requestDto(requestDto)
            .house(house)
            .build();
          
        memberRepository.save(member);
    }
}

마무리하며

사실 빌더를 사용했을 때 코드상의 큰 차이점을 아직은 잘 모르겠다. 그래도 엔티티와 DTO의 데이터 전달 방법의 새로운 길을 찾은 것 같아 기분이 좋다.

모델매퍼와 같이 정리하려 했는데 나눠 정리하는게 가독성이 좋을 것 같아 이쯤에서 마무리하려 한다. 2부에서 모델매퍼를 정리해보겠다.
참고 1

0개의 댓글