'Builder'에 해당되는 글 1건

  1. 2020.07.16 VO, DTO 구분해서 사용해야 할까?

VO 와 DTO 는 둘 다 모델에 해당하는 객체로 그 차이는 단순하다.

VO는 불변객체이고, DTO는 가변객체이다.

가변객체는 그냥 getter, setter 가 포함된 bean 을 생각하면 되고

불변객체는 setter를 포함하지 않아서 변화를 허용하지 않는 걸 말한다.

이에 DTO에는 데이터를 변환하는 비즈니스 로직이 포함될 수도 있다.

 

지금까지 DTO 같은 성격의 객체는 실무에서 많이 사용했다. 

그런데 VO 성격의 객체는 거의 사용해본 적이 없다.

불변객체...대체 언제 필요할까? 솔직히 없어도 된다.

그래도 굳이 나눠지는 개념이니 한번 생각해보자.

 

필요하긴 할거다. 접근제한자로 private 도 쓰지 않는가? 

변화를 허용하지 않기 위해 private 로 불변자원을 만든다.

객체도 "내가 처음에 만들어준 데이터 바꾸지 마" 라고 지정할 수 있는거다. 

 

프로젝트에서 VO 같은 사용자 정의 객체가 사용되는 경우를 생각해보자. 

1. DB select 를 담는 경우

2. Controller 파라미터를 담는 경우

 

그 외 비즈니스 로직에서 별도로 사용자 정의 객체가 사용되는 경우도 있겠지만

있다고 하더라도 로직에 의해 값이 유동적으로 변화하는 경우가 많기 때문에 불변인 VO로 볼 수 없다.

 

1번의 경우는 가져온 데이터를 정재하는 경우가 있기 때문에 VO로 적합하지 않다.

Controller 파라미터는 VO가 가능할 거 같다. 

그렇다면 Controller 파라미터를 vo로 해서 가질 수 있는 장점은 뭘까?

장점이 있어야 쓸 거 아닌가..

 

생각나는 장점 중 하나는 해당 VO객체가 거치게 되는 메소드나 클래스가 많을 경우

불변이 보장된다면 추후 시스템 분석이나 버그 디버깅에 도움이 될 수 있다.

일반적으로 빌링 또는 커머스시스템은 굉장히 복잡한 로직을 품고 있는데

로직이 수행되는 중에 값이 변화하지 않는다는 보장만 있다면 해당 경우의 수만 없애는 것만으로도

디버깅에 굉장히 큰 도움이 된다.

 

다만 모델객체를 구현하는 방식에 따라 가변, 불변을 모두 제공할 수 있다.

즉, 일부 데이터만 포함한 생성자에 빌더패턴을 적용하고 수정을 허용할 데이터는

별도로 setter를 만들어 주면 된다.

이렇게 되면 빌더패턴에 포함된 데이터는 불변이 되고(변경하려면 객체를 새로 생성해야 함)

포함되지 않은 데이터는 가변이 된다.

 

그렇다면 또 다시 VO, DTO를 구분하지 않고 이렇게 하나의 객체로 사용할 때 

가질 수 있는 장점은 뭐가 있을까?

가장 먼저 생각나는 것은 로직당 통일된 하나의 모델을 사용할 수 있다는 것이다.

 

예를 들어 유저정보를 수정하는 기능을 아래와 같이 만든다고 생각해보자.

 

변경될 유저정보를 받아서 그 값으로 DB 테이블을 업데이트하고 

정상적으로 업데이트 되었다면 그 값을 다시 리턴하고

업데이트에 실패했다면 DB상 최종데이터를 조회해서 리턴한다.

 

VO, DTO 를 구분할 경우 변경될 유저정보를 받을 UserVO 객체가 필요하고

DB 데이터를 담을 UserDTO 라는 객체가 필요하게 된다.

이러한 VO, DTO 는 비슷한 성격이기 때문에 아무래도 중복코드가 발생할 수 밖에 없다.

하지만 일부에만 빌더패턴을 적용한 객체를 사용할 경우 

UserModel 이라는 하나의 객체로도 충분하게 된다.

 

결국 가변, 불변 기능을 모두 포함한 모델객체를 사용하는게 가장 좋아보인다.

 

테스트 삼아 한번 만들어보자. 유저에 해당하는 모델을 만들 것이다.

 

조건은 아래와 같다.

사용할 데이터는 아이디, 이름, 나이, 등급으로 하고

이 중 아이디, 이름, 나이는 불변이고 등급은 가변으로 할 것이다.

더 나아가 아이디, 이름은 필수값으로 할 것이다.

 

완성된 모델은 아래와 같다.

@Getter
@ToString(exclude={""})
@EqualsAndHashCode(of = {"id", "name", "age"})
public class UserModel {

    @NotBlank(message = "id is required")
    private String id;
    @NotBlank(message = "name is required")
    private String name;
    private int age;
    private String grade;

    @Builder
    private UserModel(String id, String name, int age, String grade){
        Assert.hasText(id, "id is required");
        Assert.hasText(name, "name is required");
        this.id = id;
        this.name = name;
        this.age = age;
        this.grade = grade;
    }

    public void setGrade(String grade) {
        this.grade = grade;
    }
}

마지막으로 이것을 쓰는 것이 단점은 뭐가 있을까?

현재로선 없어보이는데 생각나면 추가 기록하겠다.

 

'밥벌이 > Java' 카테고리의 다른 글

XML파일의 활용  (0) 2015.09.18
BufferedStream 팁  (0) 2015.09.18
Properties 파일 읽기  (0) 2015.09.18
Posted by mypiece
,