[Spring Boot] DTO는 어떤 타입으로 정의할까? record? class? 두 타입의 차이점

Sungjin Cho·2024년 6월 3일
0

Spring Boot

목록 보기
4/15
post-thumbnail

Record란?

java 14 버전에서 출시된 새 유형의 클래스, 불변 객체를 생성할 때 사용한다.


특징

  1. 보일러 플레이트 코드 제거

다양한 함수를 기본적으로 제공해주기 때문에 보일러 플레이트 코드가 많이 빠진다.

public class LoginResponseDto {

		@JsonProperty("code")
    private String code;
    
    @JsonProperty("message")
    private String message;
    
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone="Asia/Seoul")
	  @JsonProperty("lastAccessTime")
    private LocalDateTime lastAccessTime;

    public LoginResponseDto() {
    }

    public LoginResponseDto(String code, String message, LocalDateTime lastAccessTime) {
        this.code = code;
        this.message = message;
        this.lastAccessTime = lastAccessTime;
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public LocalDateTime getLastAccessTime() {
        return lastAccessTime;
    }

    public void setLastAccessTime(LocalDateTime lastAccessTime) {
        this.lastAccessTime = lastAccessTime;
    }
}

Record로는 아래와 같이 선언된다.

위의 코드에는 없지만, equals와 hashcodetoString도 기본으로 제공해준다.

public record LoginResponseDto (

    @JsonProperty("code")
    String code,

    @JsonProperty("message")
    String message,

    @JsonProperty("lastAccessTime")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone="Asia/philippines")
    LocalDateTime lastAccessTime
) {}

API 요청 결과

{
  "code": "200",
  "message": "success",
  "lastAccessTime": "2024-06-03 17:29:43"
}

물론 Lombok의 @Getter, @AllArgsConstructor, @EqualsAndHashCode @ToString를 사용하면 줄일 수 있다.

하지만 몇십 개나 되는 DTO 클래스에 위의 어노테이션을 일일이 달아주는 게 상당히 번거로운 작업이 될 수 있다.

  1. final 필드

record의 특성 자체, 모든 필드가 final이라 변경을 못하지만, 데이터 변질에 대해 걱정하지 않아도 된다.

애초에 DTO는 말 그대로 데이터를 전송하기 위한 Object이기 때문에 수정을 못하는 것이 더 안전하게 사용할 수 있다.

  1. 바인딩

setter는 없으니, 생성자를 통해 값을 바인딩 할 수 있다. 헷갈릴 수 있는 점은, 기존에 getter가 있을때는 request.getCode() ****과 같은 형태로 getter를 통해 값을 받았지만 record의 경우엔 record.code(); 과 같이 get이 빠진 형태로 getter가 구현된다.


정리해보자면

레코드 클래스의 장단점

장점:

  • 간결성: 레코드 클래스는 데이터를 담는 클래스를 매우 간결하게 표현할 수 있다. 필드와 해당 필드에 대한 getter 메소드, equals(), hashCode(), toString() 메소드를 자동으로 제공하기 때문에 코드의 양을 크게 줄일 수 있다.
  • 불변성: 레코드 클래스의 필드는 모두 final로 선언되므로, 한번 생성된 레코드 객체의 상태는 변경되지 않습니다. 이는 객체의 안정성을 높이고, 버그 발생 가능성을 줄여준다.

단점:

  • 상속 불가: 레코드 클래스는 상속을 지원하지 않는다. 따라서 기능의 확장이 필요한 경우, 레코드 클래스 대신 일반 클래스를 사용해야 한다.
  • 빌더 패턴 미지원: 레코드 클래스는 빌더 패턴을 지원하지 않는다. 복잡한 생성 로직이 필요한 경우, 별도의 빌더 클래스를 만들어야 한다.

일반 클래스의 장단점

장점:

  • 유연성: 일반 클래스는 상속, 메소드 오버라이딩 등 레코드 클래스보다 더 다양한 기능을 제공한다. 따라서 기능의 확장이 필요한 경우, 일반 클래스를 사용하는 것이 더 유연한 해결책이 될 수 있다.
  • 빌더 패턴 지원: 일반 클래스는 빌더 패턴을 쉽게 적용할 수 있다. 복잡한 생성 로직이 필요한 경우, 빌더 패턴을 통해 객체를 안정적으로 생성할 수 있다.

단점:

  • 코드 중복: 필드에 대한 getter, setter 메소드와 equals(), hashCode(), toString() 메소드 등을 직접 작성해야 한다. 이로 인해 코드의 중복이 발생하고, 코드의 가독성이 떨어질 수 있다.
  • 불변성 미보장: 일반 클래스의 필드는 final로 선언되지 않는 한, 값이 변경될 수 있다. 이로 인해 객체의 상태가 예기치 않게 변경되는 문제가 발생할 수 있다.

참고: https://velog.io/@jinyr1128/12%EC%9B%947%EC%9D%BC-%EB%A0%88%EC%BD%94%EB%93%9C-%ED%81%B4%EB%9E%98%EC%8A%A4%EC%99%80-%EB%B9%8C%EB%8D%94-%ED%8C%A8%ED%84%B4-%EC%84%B1%EB%8A%A5-%EB%B9%84%EA%B5%90%EC%9E%A5%EB%8B%A8%EC%A0%90,
https://devjaewoo.tistory.com/160

0개의 댓글