백엔드

[자바/JAVA] 객체는 뭐로 만들어? Class, Interface, Record?

Newbie Developer 2025. 2. 12. 11:49

안녕하세요. 새내기 개발자입니다. 공부하면서 정리하는 글로 틀린 부분은 언제나 댓글로 환영합니다!

 

Java에서 DTO(Data Transfer Object)는 데이터 전송을 위해 사용되는 객체로, 일반적으로 여러 계층(Controller → Service → Repository) 간 데이터를 주고받을 때 활용됩니다.
DTO를 만들 때 사용할 수 있는 방법으로 class, record, interface 등이 있으며, 이 글에서는 각 방식의 차이점과 장단점을 살펴본 후, DTO에 자주 사용하는 어노테이션까지 정리해 보겠습니다.


1. class를 이용한 DTO

🔹 특징

  • 일반적인 클래스를 사용하여 DTO를 정의
  • 필드, 생성자, getter/setter, toString(), equals(), hashCode() 등을 포함 가능
  • 가변(Mutable) 또는 불변(Immutable) 객체로 만들 수 있음

✅ 장점

  • 가장 유연한 방법이며, Java의 모든 버전에서 사용 가능
  • 불변 객체로 만들 수 있음 (final 필드와 생성자 활용)
  • 직렬화(Serialization), 로직 추가 등의 확장이 용이

❌ 단점

  • 보일러플레이트 코드(getter, setter, 생성자 등)가 많음
  • equals() 및 hashCode()를 직접 구현해야 함 (또는 Lombok 사용)

💡 예제

public class UserDto {
    private String name;
    private int age;

    public UserDto(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() { return name; }
    public int getAge() { return age; }

    @Override
    public String toString() {
        return "UserDto{name='" + name + "', age=" + age + "}";
    }
}

2. record를 이용한 DTO (Java 14+)

🔹 특징

  • Java 14부터 도입된 불변 객체를 간편하게 정의하는 방식
  • getter, toString(), equals(), hashCode() 자동 생성
  • 모든 필드는 final이며, setter를 가질 수 없음

✅ 장점

  • 보일러플레이트 코드 최소화 (자동 생성)
  • 불변성(Immutable) 보장 → Thread-safe
  • equals(), hashCode(), toString() 자동 구현

❌ 단점

  • Java 14+에서만 사용 가능 (이전 버전과 호환되지 않음)
  • 상속 불가 (record는 클래스를 상속할 수 없음)

💡 예제

public record UserDto(String name, int age) {}

위 코드만으로 getter, toString(), equals(), hashCode()가 자동 생성됨


3. interface를 이용한 DTO

🔹 특징

  • DTO의 구조만 정의하고, 이를 구현하는 클래스를 만들거나 Proxy 기반으로 활용 가능
  • Java의 **인터페이스 기본 메서드(default)**를 활용 가능

✅ 장점

  • 여러 구현체를 만들기 용이
  • DTO의 구조만 정의할 수 있어 유연성이 높음
  • default 메서드 활용 가능

❌ 단점

  • 직접 객체 생성 불가 (class 또는 record 필요)
  • 보일러플레이트 코드 증가 가능 (구현체 필요)

💡 예제

public interface UserDto {
    String getName();
    int getAge();

    default String getFormattedName() {
        return "User: " + getName();
    }
}

// 구현체
public class DefaultUserDto implements UserDto {
    private final String name;
    private final int age;

    public DefaultUserDto(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String getName() { return name; }
    @Override
    public int getAge() { return age; }
}

4. DTO에 자주 사용하는 어노테이션

🔹 Lombok (코드 간소화)

import lombok.*;

@Getter @Setter
@NoArgsConstructor @AllArgsConstructor
@ToString @EqualsAndHashCode
@Builder
public class UserDto {
    private String name;
    private int age;
}

장점: 보일러플레이트 코드 제거, 유지보수성 향상

🔹 JSON 직렬화 (Jackson)

import com.fasterxml.jackson.annotation.*;

@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonPropertyOrder({ "age", "name" })
public class UserDto {
    @JsonProperty("full_name")
    private String name;

    @JsonIgnore
    private String password;

    private int age;
}

장점: JSON 필드명 변경, 직렬화/역직렬화 제어 가능

🔹 데이터 검증 (Validation)

import jakarta.validation.constraints.*;

public class UserDto {
    @NotNull(message = "이름은 필수입니다.")
    @Size(min = 2, max = 20)
    private String name;

    @Min(value = 18) @Max(value = 100)
    private int age;

    @Email
    private String email;

    @Pattern(regexp = "^[a-zA-Z0-9]{8,}$")
    private String password;
}

장점: 서버에서 데이터 유효성 검사 가능

🔹 JPA 연동 (Entity 변환 가능)

import jakarta.persistence.*;

@Entity
@Table(name = "users")
public class UserDto {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(nullable = false, length = 50)
    private String name;
}

장점: DTO를 엔티티로 변환 가능, DB 매핑 가능

🔹 REST API 요청/응답

import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/users")
public class UserController {
    @PostMapping
    public UserDto createUser(@RequestBody UserDto userDto) {
        return userDto;
    }
}

장점: Spring MVC에서 DTO를 요청/응답 데이터로 활용 가능


5. 정리: DTO 선택 및 어노테이션 가이드

방법 코드량 불변성 상속 직렬화 JAVA 버전
class 많음 선택 가능 O O 모든 버전
record 적음 O (불변) X O Java 14+
interface 적음 X O X 모든 버전

DTO를 쉽게 만들려면?
→ record + Lombok(@Builder) 활용

기존 Java 코드와 호환해야 한다면?
→ class + @Getter @Setter + @NoArgsConstructor

JSON 변환이 필요하다면?
→ @JsonProperty, @JsonIgnore 활용

데이터 검증이 필요하다면?
→ @NotNull, @Email, @Pattern 활용

DB와 연동이 필요하다면?
→ @Entity, @Table 활용


🔥 결론

  • DTO는 class, record, interface 중 선택 가능
  • Lombok, JSON, Validation, JPA 어노테이션을 활용하면 효율적인 DTO 설계 가능
  • 프로젝트 특성에 맞게 필요한 기능을 고려하여 DTO 설계하면 유지보수성과 생산성을 높일 수 있음 🚀