Study/java

[Java] DAO, DTO, VO 의미와 차이점, 예제

 

DAO(Data Access Object), DTO(Data Transfer Object), VO(Value Object)의 의미와 차이점을 예제와 함께 설명드리겠습니다.

 

DAO(Data Access Object)

DAO는 데이터베이스 소스에 직접 접근하는 작업을 수행하는 객체입니다.

 

예를 들어, 다음과 같은 코드가 있습니다.

private ResultSet getData(Connection connection) throws SQLException {
    PreparedStatement psmt = connection.prepareStatement("SELECT * FROM USERS WHERE ID = ?");
    psmt.setInt(1, 10);
    ResultSet resultSet = psmt.executeQuery();
    return resultSet;
}

 

데이터베이스 쿼리를 실행하고 ResultSet을 반환하는 코드입니다.

만약에 쿼리의 결과로 특정 작업을 수행하려고 한다면 ResultSet을 사용해야한다는 문제가 있습니다.

 

쿼리를 실행하고 값을 가져올 때 무조건 ResultSet의 메소드를 사용해서 가져와야합니다.

ResultSet data = getData(connection);
int id = data.getInt("id");
String name = data.getString("name");

 

DAO를 사용한다면 다음과 같이 수정할 수 있습니다.

// 설명을 위한 수도 코드입니다. 동작하지 않습니다.

// DAO 객체 생성
private class User {
    private int id;
    private String name;

    public User(int id, String name) {
        this.id = id;
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public String getName() {
        return name;
    }
}

// DAO 객체 사용
private User getUserData(Connection connection) throws SQLException {
    PreparedStatement psmt = connection.prepareStatement("SELECT * FROM USERS WHERE ID = ?");
    psmt.setInt(1, 10);
    ResultSet resultSet = psmt.executeQuery();
    return new User(resultSet.getInt("id"), resultSet.getString("name"));
}

...

// DAO를 통해 값 가져오기
User userData = getUserData(connection);
int id = userData.getId();
String name = userData.getName();

ResultSet을 사용했을 때는 ResultSet의 메소드만 사용해서 데이터를 가져올 수 있었는데, DAO 객체를 사용하니까 DAO에서 getter 메소드를 통해 데이터를 쉽게 가져올 수 있게 되었습니다.

 

 

DTO(Data Transfer Object)

DTO는 계층 간의 데이터 교환을 위해 사용되는 객체입니다.

주로 네트워크를 통해 데이터를 전송할 때 사용되며, getter와 setter를 통해 데이터에 접근합니다.

 

사용 예제는 다음과 같습니다.

// 설명을 위한 수도 코드입니다. 동작하지 않습니다.

// DTO 객체 생성
private class UserDto {
    private int id;
    private String name;

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

    public int getId() {
        return id;
    }

    public String getName() {
        return name;
    }
}

// DTO 객체 사용
public UserDto getUserInfo() throws SQLException {
    User userData = getUserData(connection);
    int id = userData.getId();
    String name = userData.getName();

    // DAO를 DTO로 변환
    return new UserDto(id, name);
}

 

UserDto라는 DTO를 생성했습니다.

그리고 DAO를 DTO로 변환하는 로직을 추가했습니다.

UserDto를 통해 각 계층에 데이터를 전달할 수 있습니다.

 

DTO를 만들지 않아도 계층 간 데이터 전달은 가능하지만, 데이터 전달을 위한 객체가 있으면 역할이 명확해지고 데이터의 일관성과 유지보수성이 향상되기 때문에 잘 사용하면 좋습니다.

 

VO(Value Object)

VO는 불변성을 보장하는 객체입니다.

DTO와 유사하지만, 생성된 후에는 값을 변경할 수 없다는 차이가 있습니다.

 

VO는 주로 특정 값이나 개념을 묘사할 때 primitive type 대신에 사용됩니다.

돈이라는 값을 표현할 때 int money 보다는 Money money로 사용하면 좀 더 명확하게 표현할 수 있습니다.

 

다음과 같이 사용할 수 있습니다.

public static void main(String[] args) {
    Age age = new Age(1999);
    System.out.println("age.getAge() = " + age.getAge());
}

private static class Age {
    private int birth;

    public Age(int birth) {
        this.birth = birth;
    }

    // 나이 계산
    public int getAge() {
        return Year.now().getValue() - birth;
    }
}

 

나이를 표현하기 위해 Age 객체를 생성했습니다.

VO를 따로 만들어서 특정 값을 표현하면 그 값과 관련된 작업들을 다 VO에서 처리할 수 있습니다.

그래서 응집도가 증가하고 가독성과 유지보수성이 증가합니다.

 

Reference

https://stackoverflow.com/questions/72025894/list-differences-dto-vo-entity-domain-model