DTO ์ VO ๋?
Data Transfer Object ์ Value Object ๋ ๊ฐ ๊ณ์ธต ๊ฐ ๋ฐ์ดํฐ ๊ตํ์ ์ํ ์๋ฐ ๊ฐ์ฒด๋ฅผ ์๋ฏธํ๋ค.
๋ฐ์ดํฐ๋ฅผ ๊ฐ ๋ ์ด์ด ๊ฐ์ ์ ๋ฌํ๋ ๋ชฉ์ ์ ๊ฐ์ง๊ณ ์์ผ๋ฉฐ, ๊ฐ์ฒด์ ์์ฑ๊ณผ getter, setter ๋ง ๊ฐ์ง๊ณ ์๋ค.
๋ ๊ฐ์ง ๋ชจ๋ ๋น์ทํ ์๋ฏธ๋ฅผ ๊ฐ์ก์ง๋ง ์ฐจ์ด์ ์ด ์๋ค.
VO ๋?
VO ๋ ๋๋ฉ์ธ์์ ํ ๊ฐ ๋๋ ๊ทธ ์ด์์ ์์ฑ๋ค์ ๋ฌถ์ด์ ํน์ ๊ฐ์ ๋ํ๋ด๋ ๊ฐ์ฒด๋ฅผ ์๋ฏธํ๋ค.
์ด๋ก ์ธํด ๊ฐ์ฒด๋ฅผ ๊ฐ์ฒ๋ผ ์ฌ์ฉํ ์ ์๊ณ , ์์ฑ์๋ฅผ ํตํด ์ค์ ๋ ์ํ ๊ฐ์ ์ ๋ ๋ณํ์ง ์๋๋ค.
ํ ์๋ก ๋ก๋ ๋ฒํธ๋ฅผ ์๊ฐํด๋ณด์.
๋ก๋ ๋ฒํธ๋ ์ถฉ๋ถํ int
ํ์
์ผ๋ก ์ฌ์ฉํด๋ ๋์ง ์์๊น?
์ฌ์ฉํ ์ ์์ง๋ง ๋ถ์ ์ ํ๋ค๊ณ ๋ณผ ์ ์๋ค.
๋๋ฉ์ธ ๊ฐ์ฒด๋ฅผ ๋ํ๋ด๊ธฐ ์ํด ์์ ๊ฐ์ ์ฌ์ฉํ๋ ๋์ ๊ด์ต์ primitive obsession
์ด๋ผ ๋ถ๋ฆด ์ ๋๋ค.
๋ก๋ ๋ฒํธ๋ 1 ์์ 45 ์ ์ซ์๋ก ๋ฒ์๊ฐ ์ ํด์ ธ ์์ผ๋ฉฐ ์๋ก์ ๋ํ ์ฐ์ฐ์ด ๊ฐ๋ฅํ์ง ์๊ธฐ ๋๋ฌธ์ LottoNumber
๋ผ๋ VO ๋ฅผ ํตํด ๊ด๋ฆฌํ๋ ๊ฒ์ด ํจ๊ณผ์ ์ด๋ค.
VO ์ ํน์ฑ
1. Immutable(๋ถ๋ณ์ฑ) - setter ๊ฐ ์๋ ๋ถ๋ณ ๊ฐ์ฒด์ฌ์ผ ํ๋ค.
์์ฑ ๊ฐ ์์ฒด๊ฐ ์๋ณ ๊ฐ์ธ VO ๋ ๊ฐ์ด ๋ฐ๋๋ฉด ๋ค๋ฅธ ๊ฐ์ด ๋์ด ์ถ์ ์ด ๋ถ๊ฐํ๊ณ , ๋ณต์ฌ๋ ๋๋ ์๋์น ์์ ๊ฐ์ฒด๋ค์ด ํจ๊ป ๋ณ๊ฒฝ๋๋ ๋ฌธ์ ๋ฅผ ์ ๋ฐํ๋ค.
๋ฐ๋ผ์ VO ๋ ๋ฐ๋์ ๋ณ๊ฒฝํ ์ ์๋ ๋ถ๋ณ ๊ฐ์ฒด๋ก ๋ง๋ค์ด์ผ ํ๋ค.
public class LottoNumber {
private int value;
public LottoNumber(int value) {
this.value = value;
}
}
public static void main(String[] args) {
LottoNumber lottoNumber1 = new LottoNumber(1);
LottoNumber lottoNumber2 = new LottoNumber(1);
lottoNumber2 = new LottoNumber(2);
}
๋ฐ๋ผ์ ๊ฐ์ฒด ์์ฑ ์ดํ ์์ฑ ๊ฐ์ด ๋ณ๊ฒฝ๋ ์ฌ์ง๊ฐ ์๋ setter ๋ฅผ ์ฌ์ฉํ๋ ๊ฒ ๋ณด๋ค ์์ฑ๊ณผ ๋์์ ์์ฑ ๊ฐ์ ํ ๋นํ๋ ์์ฑ์๋ฅผ ํ์ฉํ๋ ๊ฒ์ด VO ์ ์ ์ฒด์ฑ์ ์งํค๋ฉด์ ์๋์น ์์ ๋ณ๊ฒฝ์ ๋ง์ ์ ์๊ณ ์ ์ง๋ณด์์๋ ํจ๊ณผ์ ์ด๋ค.
์ด๋ก์จ VO ๋ GC ์ ์ํด ํ๊ธฐ ๋ ๋๊น์ง ๋์ผํจ์ ๋ณด์ฅํ๋ค.
1.1 Hassle-free Sharing(๋ฒ๊ฑฐ๋ก์ ์๋ ๊ณต์ )
VO ๋ ์ฝ๋์ ๋ค๋ฅธ ๋ถ๋ถ์ ์ํด ์์ ๋์ง ์๊ธฐ ๋๋ฌธ์ ์ฐธ์กฐ๋ก ๊ณต์ ํ ์ ์๋ค.
์ด๋ side effect ๋ฅผ ํผํ๊ธฐ ์ํด ์ฌ์ฉ๋๋ ์ฝ๋์ ๋ณต์ก์ฑ๊ณผ ๋ถํ๋ฅผ ๊ทน์ ์ผ๋ก ๊ฐ์์ํจ๋ค.
1.2 Improved Semantics(ํฅ์๋ ์๋ฏธ)
์ด๊ธฐ ํด๋์ค์๋ ์์ฑ์์ private
์์ฑ๋ง ์กด์ฌํด์ผํ๋ค.
์ด๋ฅผ ํตํด ๋ฌด์๋ฏธํ ์ธํฐํ์ด์ค๋ฅผ ํผํ๊ณ VO ์ ๋ํ ์๋ฏธ์๋ ์ด๋ฆ๊ณผ ๋์์ ์ ์ํ ์ ์๋ค.
2. Value Equality(๊ฐ ๋๋ฑ์ฑ) - equals ์ hashCode ๋ฉ์๋๋ฅผ ์ฌ์ ์ํด์ผ ํ๋ค.
ํ์ ๋ ๊ฐ๊ณ , ๋ด๋ถ ์์ฑ๊ฐ๋ ๊ฐ์ ๋ ๊ฐ์ฒด๊ฐ ์๋ค๋ฉด ์ค์ ๋ก๋ ๊ฐ์ ๊ฐ์ฒด๋ก ์ทจ๊ธํ๋ ๊ฒ์ด ์ด์์ ์ด๋ค.
public class LottoNumber {
private int value;
public LottoNumber(int value) {
this.value = value;
}
}
@Test
void equals() {
LottoNumber lottoNumber1 = new LottoNumber(5);
LottoNumber lottoNumber2 = new LottoNumber(5);
// lottoNumber1 != lottoNumber2
assertThat(lottoNumber1 == lottoNumber2).isFalse(); // ๋์ผ์ฑ ๋น๊ต
}
ํ์ง๋ง ๊ฐ์ด ๊ฐ์ ๋ ๊ฐ์ฒด๋ฅผ ์์ฑํ๊ณ ๋์ผ์ฑ ๋น๊ต๋ฅผ ํด๋ณด๋ฉด ์๋ก ๋ค๋ฅธ ๊ฐ์ฒด๋ก ๊ตฌ๋ณ๋๋ค.
๋ ๊ฐ์ฒด๊ฐ ์ฐธ์กฐํ๊ณ ์๋ ๋ฉ๋ชจ๋ฆฌ ์ฃผ์๊ฐ์ด ์๋ก ๋ค๋ฅด๊ธฐ ๋๋ฌธ์ด๋ค.
๋ฐ๋ผ์ ๊ฐ์ฒด๊ฐ ํฌํจํ๊ณ ์๋ ์์ฑ๊ฐ๋ค์ ๊ธฐ์ค์ผ๋ก ๊ฐ์ฒด๋ฅผ ๋น๊ตํ๋ ๋๋ฑ์ฑ ๋น๊ต๋ฅผ ํตํด ๊ฐ์ฒด๋ฅผ ๋น๊ตํด์ผ ํ๋ค.
ํ์ง๋ง ์ด๋ค ์์ฑ๊ฐ๋ค์ ๊ธฐ์ค์ผ๋ก ๋๋ฑ์ฑ ๋น๊ต๋ฅผ ํ ๊ฒ์ธ์ง๋ ์ง์ equals()
๋ฉ์๋๋ฅผ ์ฌ์ ์ํ์ฌ ์ ํด์ผ ํ๋ค.
// equals & hashcode ์ฌ์ ์
...
@Override
public boolean equals(final Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
final LottoNumber lottoNumber = (LottoNumber) o;
return value == lottoNumber.value;
}
@Override
public int hashCode() {
return Objects.hash(value);
}
...
hashCode()
๋ฅผ ์ฌ์ ์ํ์ง ์์ผ๋ฉด ๋ฉ๋ชจ๋ฆฌ ์ฃผ์๊ฐ์ ์ฌ์ฉํด์ ํด์๊ฐ์ ๋ง๋ ๋ค.
hashCode()
๋ฅผ ์ฌ์ ์ ํด์ค์ผ๋ก์จ ๊ฐ์ฒด์ ํน์ ๊ฐ์ ๊ธฐ์ค์ผ๋ก ๊ฐ์ ํด์์ฝ๋๋ฅผ ์ป์ ์ ์๊ณ , ์ด๋ ํด์๊ฐ์ ์ฌ์ฉํ๋ ์ปฌ๋ ์
๋ฑ์์ ๊ฐ์ฒด๋ฅผ ๋น๊ตํ๋ ์ฉ๋๋ก ์ฌ์ฉ๋๊ธฐ ๋๋ฌธ์ equals()
๋ฉ์๋ ์ฌ์ ์ ์ hashCode()
๋ ํจ๊ป ์ฌ์ ์ ํด์ฃผ๋ ๊ฒ์ด ํจ๊ณผ์ ์ด๋ค.
๋จ, ๋ฌด์๋ฏธํ equals()
์ hashCode()
๋ ์ฌ์ฉํ์ง ์์์ผ ํ๋ค.
3. Self Validation(์๊ฐ ์ ํจ์ฑ ๊ฒ์ฌ) - ์์ฑ์์์ validate
VO ๋ context ์์ ์ ํจํ ๊ฐ๋ง ํ์ฉํ๋ค. ์ด๋ ์ ํจํ์ง ์๋ ๊ฐ์ผ๋ก ๊ฐ์ฒด๋ฅผ ๋ง๋ค ์ ์์์ ์๋ฏธํ๊ธฐ๋ ํ๋ค.
์์ฑ์ ๋ด๋ถ์์ ์ ํจ์ฑ ๊ฒ์ฌ๋ฅผ ์ํํจ์ผ๋ก์จ ๋ชจ๋ ์ ํจ์ฑ ๊ฒ์ฌ๋ฅผ ์์ฑ ์๊ฐ์ ์ด๋ฃจ์ด์ง๊ฒ๋ ํ ์ ์๋ค.
์ด๋ฌํ ๊ฐ์ ์ ํจ์ฑ ๊ฒ์ฌ๋ ์๋ฏธ์๊ณ ๋ช ์์ ์ธ ๋ฐฉ๋ฒ์ผ๋ก ๋๋ฉ์ธ ์ ์ฝ ์กฐ๊ฑด์ ํํํ๋๋ฐ๋ ์ ์ฉํ๋ค.
public class LottoNumbers {
private final List<LottoNumber> lottoNumbers;
private LottoNumbers(List<LottoNumber> lottoNumbers) {
// validateLottoNumbers(lottoNumbers); 1๋ฒ ์ฐ๋ ๋์์ ๊ฒ์ฆ
// 2๋ฒ ์ฐ๋ ๋์ ์ธ๋ถ ๋ฉ์๋์์ lottoNumbers ๋ฅผ ๋ณ๊ฒฝ
// this.lottoNumbers = new ArrayList<>(lottoNumbers); ๋ณ๊ฒฝ๋ ๊ฐ์ด ํ ๋น
this.lottoNumbers = new ArrayList<>(lottoNumbers);
validateLottoNumbers();
}
public static LottoNumbers of(List<Integer> rawLottoNumbers) {
...
return new LottoNumber(lottoNumbers);
}
private void validateLottoNumber() {
...
}
}
๊ฐ ์ฃผ์
ํ validate
๋ฅผ ์งํํ๋ ๊ฒ์ ๋ฐฉ์ด์ ๋ณต์ฌ ๊ธฐ๋ฒ์ด๋ผ ํ๋๋ฐ, ์ด๋ Multi-Thread ํ๊ฒฝ์ ์์ ํ๋ค.
Multi-Thread ํ๊ฒฝ์์๋ validate
๋ฅผ ๋ง์น lottoNumber
๋ฅผ ๋ค๋ฅธ ์ฐ๋ ๋์์ ๋ณ๊ฒฝํ๊ฒ๋๋ฉด ๋ณ๊ฒฝ๋ ์ํ๋ก ๊ฐ์ฒด์ ํ ๋น๋๊ธฐ ๋๋ฌธ์ validate
๋ฅผ ํ์์๋ก ๋ฏธ๋ฃจ๋ ๊ฒ์ด๋ค.
VO ๋ ์์๊ฐ ํฌ์ฅ๊ณผ ๊ฐ์๊ฐ?
๊ฒฐ๋ก ๋ถํฐ ๋งํ์๋ฉด ๋ค๋ฅด๋ค. ์์๊ฐ ํฌ์ฅ๊ณผ ๋์์ VO ๋ก ๋ง๋ค ์ ์์ง๋ง, ์์๊ฐ ํฌ์ฅ์ด VO ๋ ์๋๋ค.
์์๊ฐ ํฌ์ฅ
์์ ์ ํ์ ๊ฐ์ ์ด์ฉํด ์๋ฏธ๋ฅผ ๋ํ๋ด์ง ์๊ณ , ์๋ฏธ์๋ ๊ฐ์ฒด๋ก ํฌ์ฅํ๋ค๋ ๊ฐ๋
VO
- Immutability(๋ถ๋ณ์ฑ) - ์์ ์(setter)๊ฐ ์๋ค.
- Value Equality(๊ฐ ๋๋ฑ์ฑ) - ๋ด๋ถ ๋๋ฑ์ฑ ๊ฒ์ฌ.
- Self Validation(์๊ธฐ ์ ํจ์ฑ ๊ฒ์ฌ) - ์์ฑ์์์ validate.
DTO ๋?
DTO ๋ ๊ณ์ธต ๊ฐ ๋ฐ์ดํฐ ๊ตํ์ ์ํด ์ฌ์ฉ๋๋ ๊ฐ์ฒด๋ก, ๋ก์ง์ ๊ฐ์ง์ง ์๊ณ getter ์ setter ๋ง ๊ฐ๊ณ ์๋ ์์ํ ๋ฐ์ดํฐ ๊ฐ์ฒด๋ค.
์๋ฅผ ๋ค์ด ์ ์ ๊ฐ ์ ๋ ฅํ ๋ฐ์ดํฐ๋ฅผ DB ์ ๋ฃ๋ ๊ณผ์ ์ ๋ณด์.
์ ์ ๊ฐ ์์ ์ ๋ธ๋ผ์ฐ์ ์์ ๋ฐ์ดํฐ๋ฅผ ์ ๋ ฅํ์ฌ form ์ ์๋ ๋ฐ์ดํฐ๋ฅผ DTO ์ ๋ฃ์ด์ ์ ์กํ๋ค.
ํด๋น DTO ๋ฅผ ๋ฐ์ ์๋ฒ๊ฐ DAO ๋ฅผ ์ด์ฉํ์ฌ DB ๋ก ๋ฐ์ดํฐ๋ฅผ ์ง์ด๋ฃ๋๋ค.