티스토리 뷰

Dev/Design Pattern

VO(Value Object) & DTO(Data Transfer Object) vs Map

꿈을 위해 잠을 잊은 그대에게 2020. 7. 1. 22:21

Q) VO와 Map의 차이는? 언제 VO를 쓰고 언제 Map 써야하는가? => 목적에 맞게

 

Java Beans

일반적으로 자바빈은 속성과, 그 속성에 대한 getter, setter 메서드로 구성된 데이터 객체(VO, Value Object)를 말하며 데이터 전송에 사용되는 객체를 말한다.

 

자바로 작성된 재사용 가능한 소프트웨어 컴포넌트

 

getter, setter 메서드를 통해 컴포넌트에 접근가능

 

VO (Value Object)

데이터 그 자체로 의미 있는 것을 담고 있는 객체

 

DTO와 동일한 개념이나 차이점은 Read–Only 속성 객체이다.

 

간단한 독립체( Entity )를 의미하는 작은 객체를 의미한다.

 

**VO vs DTO

DTO (Data Transfer Object)

계층간 데이터 교환을 위한 객체

 

일반적인 DTO는 로직을 가지고 있지 않다. 순수한 데이터 객체이며 속성과 속성에 접근하기 위한 getter, setter메서드로만 구성되는 POJO (** POJO: 특정 인터페이스 또는 클래스를 상속하지 않는 일반 자바 개체)

 

Map

Key와 Value의 쌍으로 값을 저장하는 컬렉션

 

‘사람’을 예로 들면 누구든지 "이름" = "홍길동", "생일" = "몇 월 몇 일" 등으로 구분할 수 있다. 자바의 맵(Map)은 이러한 대응관계를 쉽게 표현할 수 있게 해 주는 자료형이다.

 

 

 

public class MemberVO {
	private String id;
	private String pwd;
	private String name;
	private String email;
	private Date joinDate;

	public MemberVO() {}

	public MemberVO(String id, String pwd, String name, String email) {
		this.id = id;
		this.pwd = pwd;
		this.name = name;
		this.email = email;
	}

	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	public String getPwd() {
		return pwd;
	}

	public void setPwd(String pwd) {
		this.pwd = pwd;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getEmail() {
		return email;
	}

	public void setEmail(String email) {
		this.email = email;
	}

	public Date getJoinDate() {
		return joinDate;
	}

	public void setJoinDate(Date joinDate) {
		this.joinDate = joinDate;
	}

}

 

VO 작성 시, getter, setter(Data Access Method)가 왜 필요한건지?

 

VO에 getter, setter를 쓰는 경우

변수에 새로운 값을 할당할 때마다 validation 검사 가능

lazy loading 가능

read와 write 권한 다르게 설정 가능(public, private 사용)

 

getter, setter는 캡슐화(encapsulation)를 구현하는 가장 기본적인 형태이다. 언뜻보면 그냥 변수를 public으로 선언하여 접근하는 것과 별반 달라보이지 않는다. 하지만 public으로 선언하여 외부에서 객체의 각 변수에 접근하여 값을 변경하는 경우가 발생할 수 있다.

 

객체의 상태는 오직 그 객체의 동작에 의해서만 접근/변경되도록 하는 게 맞다. 한 객체가 다른 객체의 필드를 변경하려는 경우, public method를 통해 객체의 상태(필드 값)를 변경해야 한다. 또한 외부에서 접근 가능한 public method는 최소한으로 해야한다.

 

 

Q. 캡슐화를 위한 방법으로 getter, setter 밖에 없는걸까?

 

getter, setter 메서드로 접근할 수 있도록 하는 것이 진정한 캡슐화가 맞냐는 의문들도 많다.

캡슐화를 위해 사용했다고 하면, getter, setter말고는 다른 방법이 없는 것인지 궁금하다.

또, 데이터 객체에 대한 정보 은닉이 항상 필요한가??

 

결론부터 이야기하자면, OOP(객체지향 프로그래밍)를 지향한다면 반드시 필요하다.

(**진짜 객체지향은 정보은닉에서 시작된다.)

 

그러나 C#의 경우는 Property, Auto Property 같은 개념이 있는데, 접근자 메서드가 굳이 필요하지 않다면 일반 변수처럼 사용이 가능하다. 즉, getter, setter가 필요 없는 경우에는 굳이 작성할 필요가 없다는 것이다. 물론 Java의 경우도 Lombock의 어노테이션을 사용해서 해결할 수 있다.

 

 

 

Map vs VO

 

Map 사용 시

장점

개발 시 권장사항이 select 시에는 Map을 사용하여야 하는 경우 Map을 권장

 

select를 사용하는 경우는 보통 2개 이상의 테이블을 조인하여 조회하는 경우가 많아 VO로는 표현이 복잡하기 때문에 Map을 사용한다.

   

단점

Map의 key 또는 value가 null인 경우 Map은 해당 필드 자체를 key로 가져가지 않는다.

 

따라서 쿼리 수행 시, key 값 자체가 존재하지 않아 오류 발생 (이 경우를 대비하여 쿼리에 jdbcType 선언 필요, 해당 값이 null일 경우 초기화 타입 지정) 여러 타입을 담아야 하기 때문에 Map은 Value 선언 시 Object로 할 수 밖에 없다.

 

그러나 Object는 최상위 타입이기 때문에 type이 매치되지 않는 경우가 발생해도 실제로 돌려보지 않는 한 알 수가 없다. Object로 선언하여 모든 타입을 담기 때문에, 부가적인 casting 작업이 발생 가능하다.

 

VO 사용 시

장점

비즈니스 로직 상 데이터가 명확해야 하는 경우 VO 권장 (ex: 정산, 공수 산정, 매표 등)

 

특정 값의 key 또는 value(필수 값인 경우)가 null 인 경우 VO 클래스 내에 선언된 타입으로 초기화 수행됨. 쿼리 수행 시 null로 인한 오류가 나지 않음

 

멤버변수에 대한 구체적인 타입을 선언하기 때문에 타입이 매치되지 않는 경우 컴파일 에러가 발생하여 바로 알아챌 수 있다.

 

반드시 값이 필요한 변수에 대해 생성자 파라미터로 필요한 값을 넣을 수 있어, 이 값이 없는 경우 컴파일 에러가 발생한다.

 

단점

Map에 비해 소스가 많아진다.

 

getter, setter 메서드를 일일이 작성해주어야 하는 번거로움이 있었지만 현재 Lombock을 사용하면 annotation 형태로 조금 더 간편하게 사용 할 수 있다 (@Getter, @Setter)

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크