ํ๋ก๊ทธ๋๋ฐ์ ํ๋ฉฐ, VO(Value Object)๋ผ๋ ๋จ์ด๋ฅผ ๋ค์ด๋ณด์
จ์๊ฒ๋๋ค.
ํ์ง๋ง VO๋ผ๋ ๋จ์ด๊ฐ ์ค๋ฌด์์ ํผ๋์ค๋ฝ๊ฒ ์ฐ์ด๊ณ ์์ต๋๋ค.
๊ตฌ๊ธ์ VO๋ฅผ ๊ฒ์ํด๋ณด๋ฉด ์์ง๋ ์ฌ๋ฌ ๊ธ๋ค์ด Getter/Setter๋ง ์๋๊ฐ์ ์ค์ด๋๋ฅด๋ ๊ฐ์ฒด๋ฅผ
VO๋ผ ์นญํ๊ณ ์๋๋ฐ ์ด๋ DTO๋ก ์นญํ๋๊ฒ ํผ๋์ ์ฌ์ง๊ฐ ์ ์ต๋๋ค.
๊ทธ๋ ๋ค๋ฉด, VO์ ๋ํด์ ์์๋ด
์๋ค
Martin Fowler์ ๊ธ์ ์ํ๋ฉด
โ๐ผI find it useful to think of two classes of object:
ย ย ย ย ย value objects and reference objects, depending on how I tell them apart
๐๋๋ ๊ตฌ๋ณํ๋ ๋ฐฉ๋ฒ์ ๋ฐ๋ผ ๊ฐ ๊ฐ์ฒด์ ์ฐธ์กฐ ๊ฐ์ฒด,
ย ย ย ย ย ๋ ๊ฐ์ง ํด๋์ค์ ๊ฐ์ฒด๋ฅผ ๊ณ ๋ คํ๋ ๊ฒ์ด ์ ์ฉํ๋ค๋ ๊ฒ์ ์๊ฒ๋์๋ค.
โ๐ผOne source of terminological confusion is that around the turn of the century
ย ย ย ย ย some J2EE literature used "value object" for Data Transfer Object.
ย ย ย ย ย That usage has mostly disappeared by now, but you might run into it.
๐์ฉ์ด์ ํผ๋์ด ์จ๊ฒ์ ์ธ๊ธฐ๊ฐ ๋ฐ๋ ๋ฌด๋ ต J2EE๋ฌธํ์์
ย ย ย ย ย Date Tranfer Object๋ฅผ Value Object๋ผ๊ณ ์ฌ์ฉํ์๊ธฐ ๋๋ฌธ์ด๋ค.
ย ย ย ย ย ๊ทธ๋ฌํ ์ฌ์ฉ์ ์ง๊ธ์ผ๋ก์๋ ๋๋ถ๋ถ ์ฌ๋ผ์ก์ง๋ง, ๋๋ ์ฌ์ ํ ์ฐ์ฐํ ์ ํ ์ ์์ ๊ฒ์ด๋ค
๊ทธ๋ ๋ค๋ฉด, Value-Object์ Reference-Object๋ฅผ ๊ตฌ๋ถํ๋ ๋ฐฉ๋ฒ์ ์์๋ด ์๋ค.
Martin Fowler๊ฐ ์ธ๊ธํ VO์ ๊ฐ์๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
โ๐ผWhen programming, I often find it's useful to represent things as a compound.
ย ย ย ย ย A 2D coordinate consists of an x value and y value.
ย ย ย ย ย An amount of money consists of a number and a currency.
ย ย ย ย ย A date range consists of start and end dates,
ย ย ย ย ย which themselves can be compounds of year, month, and day.
๐ํ๋ก๊ทธ๋๋ฐํ ๋, ์ฌ๋ฌผ์ ๋ณตํฉ๋ฌผ๋ก ํํํ๋ ๊ฒ์ด ์ ์ฉํ ๊ฒฝ์ฐ๊ฐ ์ข ์ข ์๋ค.
ย ย ย ย ย ์๋ฅผ ๋ค์ด, 2์ฐจ์ ์ขํ๋ x, y๋ก ์ด๋ฃจ์ด์ ธ ์๊ณ ,
ย ย ย ย ย ๋์ด๋ ํตํ ๊ฐ์ ๊ฒฝ์ฐ ์ซ์๋ก ์ด๋ฃจ์ด์ ธ ์๋ค.
ย ย ย ย ย ๋ ์ง์ ๋ฒ์๋ ์์ ๋ ์ง์ ์ข ๋ฃ๋ ์ง๋ก ๊ตฌ์ฑ๋ ์ ์๊ณ ,
ย ย ย ย ย ์ฐ๋์ ์, ์ผ์ ๋ณตํฉ๋ฌผ์ผ ์ ๋ ์๋ค.
์ฆ, Value-Object ๋, ํ๊ฐ ํน์ ๊ทธ ์ด์์ ์์ฑ๋ค์ ๋ฌถ์ด์ ํน์ ๊ฐ์ ๋ํ๋ด๋ ๊ฐ์ฒด๋ฅผ ๋งํฉ๋๋ค.
VO๋ ๋๋ฉ์ธ ๊ฐ์ฒด์ ์ผ์ข
์ด๋ฉฐ, ๋ณดํต ๊ธฐ๋ณธํค๋ก ์๋ณ ๊ฐ์ ๊ฐ๋ Entity์ ๊ตฌ๋ณํด์ ์ฌ์ฉํฉ๋๋ค.
๊ทธ๋ ๋ค๋ฉด VO๋ ์ด๋ค ์กฐ๊ฑด๋ค์ ์ํด ๊ตฌ๋ถํด์ ์ฌ์ฉํ๋์ง ์์๋ด
์๋ค.
์ผ๋ฐ์ ์ผ๋ก ํ์ ์ด ๊ฐ๊ณ , ๋ด๋ถ์ ์์ฑ ๊ฐ๋ ๊ฐ์ ๋ ๊ฐ์ฒด๊ฐ ์๋ค๋ฉด, ๋ ๊ฐ์ฒด๋ ๊ฐ์ ๊ฐ์ฒด๋ผ๊ณ ์ทจ๊ธํ ๊ฒ ์ ๋๋ค.
์คํ๋ ค ๋ค๋ฅด๋ค๊ณ ํ๋๊ฒ ๋ ์ด์ํ๋ค๊ณ ์๊ฐ ํ ์ ๋ ์์ต๋๋ค.
์๋ฅผ๋ค๋ฉด, ๋นจ๊ฐ์์ด ๋นจ๊ฐ์๊ณผ ๋ค๋ฅด๋ค๊ณ ํ๋๊ฒ๊ณผ ๊ฐ์ต๋๋ค.
ํ์ง๋ง ์ค์ ๋ก, ๊ฐ์ด ๊ฐ์ ๋ ๊ฐ์ฒด๋ฅผ ์์ฑํ๊ณ ๊ฐ์ฒด๋ฅผ ๋น๊ตํด๋ณด๋ฉด ๋์ ์๋ก ๋ค๋ฅธ ๊ฐ์ฒด๋ก ๋น๊ต๋ฉ๋๋ค.
์ขํ๋ฅผ ์์๋ก ํ ์ฝ๋๋ฅผ ๋ณด๋ฉด,
public class Point {
private int x;
private int y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
}
@Test
public void isPointEquals() {
Point point1 = new Point(1, 2);
Point point2 = new Point(1, 2);
// point1 != point2
Assertions.assertThat(point1 == point2).isFalse();
}
ํ
์คํธ ์คํ ์ ๊ฐ์ ๊ฐ์ ๊ฐ์ง ์ขํ 1๊ณผ ์ขํ2๋ ๋ค๋ฅธ ๊ฐ์ฒด๋ผ๋๊ฑธ ์ ์ ์์ต๋๋ค.
๋ถ๋ช
์ฌ๋์ด ๋ณด๊ธฐ์ ๊ฐ์ ๊ฐ์ ๊ฐ์ง ์ขํ๋ ๊ฐ์ ์ขํ์ธ๋ฐ ๋ค๋ฅธ ์ขํ๋ผ๊ณ ํฉ๋๋ค.
์ด๋ฌํ ์ ์ ์ฐ๋ฆฌ๊ฐ ํ์ค๊ณผ ๊ฐ์ ๋๋ฉ์ธ์ ์ค๊ณํ๊ณ ๊ฐ์ฒด๋ฅผ ์ฌ์ฉํ๋ ์ ์ ์์ด ํผ๋์ ์ค๋๋ค.
์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด์๋ ๋์ผ์ฑ ๋น๊ต์ ๋๋ฑ์ฑ ๋น๊ต์ ์ฐจ์ด์ ๋ํด ์์์ผํฉ๋๋ค.
๋์ผ์ฑ ๋น๊ต
๐ ๋์ผ์ฑ ๋น๊ต๋ ํด๋น ๊ฐ์ฒด๊ฐ ์ฐธ์กฐํ๊ณ ์๋ ์ฃผ์ ๊ฐ์ ํ์ธํฉ๋๋ค.
ย ย ย ย ย ย ํ์ง๋ง ํ์ฌ ์ํ์์ Point1๊ณผ Point2๊ฐ ์ฐธ์กฐํ๊ณ ์๋ ๋ฉ๋ชจ๋ฆฌ์ ์ฃผ์ ๊ฐ์ ๋ค๋ฅด๋ฉฐ,
ย ย ย ย ย ย ์ด ์ฃผ์ ๊ฐ์ ์์๋ก ๋ฐ๊ฟ ์ ์์ต๋๋ค.
๋๋ฑ์ฑ ๋น๊ต
๐ ๋๋ฑ์ฑ ๋น๊ต๋ ๊ฐ์ฒด๊ฐ ํฌํจํ๊ณ ์๋ ์์ฑ ๊ฐ์ ๊ธฐ์ค์ผ๋ก ๊ฐ์ฒด๋ฅผ ๋น๊ตํฉ๋๋ค.
ย ย ย ย ย ย ์ด๋ฌํ ๋๋ฑ์ฑ ๋น๊ต๋ฅผ ๊ตฌํํ๊ธฐ ์ํด์๋ equals ๋ฉ์๋๋ฅผ ์ฌ์ ์ํจ์ผ๋ก์จ ๊ฐ๋ฅํด์ง๋๋ค.
ย ย ย ย ย ย equals ๋ฉ์๋ ์ฌ์ ์ ์์๋ ์ด๋ ํ ์์ฑ ๊ฐ๋ค์ ๊ธฐ์ค์ผ๋ก ๋๋ฑ์ฑ์ ๋น๊ตํ ๊ฒ์ธ์ง ์ ํด์ผํฉ๋๋ค.
์์ Point ๊ฐ์ฒด์ equals ๋ฉ์๋์ hashCode ๋ฉ์๋๋ฅผ ์ฌ์ ์ ํด๋ด ์๋ค.
...
// equals & hashcode ์ฌ์ ์
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
final Point point = (Point) o;
return x == point.x &&
y == point.y;
}
@Override
public int hashCode() {
return Objects.hash(x, y);
}
...
๐๊ฐ์ฒด์ hash code๋ ๊ฐ์ฒด๋ฅผ ์๋ณํ ํ๋์ ์ ์ ๊ฐ์ ๊ฐ๋ฆฌํค๊ณ ,
ย ย ย ย ย ย ์ฌ์ ์ ํ์ง ์์ผ๋ฉด ๋ฉ๋ชจ๋ฆฌ ์ฃผ์ ๊ฐ์ ์ฌ์ฉํด์ ํด์ฌ ๊ฐ์ ๋ง๋ญ๋๋ค.
ย ย ย ย ย ย ๊ฐ์ฒด์ ๋๋ฑ์ฑ์ ๋น๊ตํ ๋๋ hashCode ๋ฉ์๋๋ฅผ ์ฌ์ ์ํ์ฌ,
ย ย ย ย ย ย ํน์ ๊ฐ์ ๊ธฐ์ค์ผ๋ก ๊ฐ์ ํด์ฌ ์ฝ๋๋ฅผ ์ป์ ์ ์๊ณ ,
ย ย ย ย ย ย ์ด๋ ํด์ฌ ๊ฐ์ ์ฌ์ฉํ๋ ์ปฌ๋ ์ ๋ฑ์์ ๊ฐ์ฒด๋ฅผ ๋น๊ตํ๋ ์ฉ๋๋ก ์ฌ์ฉ๋ฉ๋๋ค.
์ฌ์ ์ ํ equals ๋ฉ์๋์ hashCode ๋ฉ์๋๋ฅผ Test ํด๋ด ์๋ค.
...
@Test
public void isPointAttributesEquals() {
Point point1 = new Point(1, 2);
Point point2 = new Point(1, 2);
// point1 == point2
Assertions.assertThat(point1.equals(point2)).isTrue();
// point1.hashCode() == point2.hashCode()
Assertions.assertThat(point1.hashCode() == point2.hashCode()).isTrue();
}
...
์ด์ฒ๋ผ equals ๋ฉ์๋์ hashCode ๋ฉ์๋๋ฅผ ์ฌ์ ์ํ๋ฉด,
VO๋ฅผ ์ฌ์ฉํ ๋ ์์ฑ๊ฐ์ด ๊ฐ์ ๊ฐ์ฒด๋ ๊ฐ์ ๊ฐ์ฒด์์ ๋ณด์ฅํ๋ฉด์ VO๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค.
Entity์ ๊ฐ์ ๊ฒฝ์ฐ ๋ณ๋์ ์๋ณ ๊ฐ์ ๊ฐ์ง๊ณ ์๊ธฐ ๋๋ฌธ์
๋ด๋ถ ์์ฑ ๊ฐ์ด ๋ณ๊ฒฝ๋๋ค๊ณ ํ๋๋ผ๋ ๊ฐ์ ๊ฐ์ฒด๋ก ๊ณ์ ์ธ์ํ๊ณ ์ถ์ ํ ์ ์์ต๋๋ค.
ํ์ง๋ง ์์ฑ ๊ฐ ์์ฒด๊ฐ ์๋ณ ๊ฐ์ธ VO๋ ์์ฑ ๊ฐ์ด ๋ฐ๋๊ฒ ๋๋ฉด ์๋ณ ๊ฐ๋ ๋ฐ๋๊ฒ ๋์ด ์ถ์ ์ด ๋ถ๊ฐ๋ฅํ๊ณ ,
๋ณต์ฌ ๋ ๋๋ ์๋์น ์์ ๊ฐ์ฒด๋ค์ด ํจ๊ป ๋ณ๊ฒฝ๋๋ ๋ฌธ์ ๋ฅผ ์ ๋ฐํฉ๋๋ค.
๋ฐ๋ผ์ VO๋ ๊ฐ์ ๋ณ๊ฒฝํ ์ ์๋ ๋ถ๋ณ ๊ฐ์ฒด๋ก ๋ง๋ค์ด์ผํฉ๋๋ค.
์์๋ฅผ ํตํด ๋ถ๋ณ ๊ฐ์ฒด๋ก ๋ง๋ค์ด์ผํ๋ ์ด์ ๋ฅผ ์์๋ด ์๋ค.
@Getter
@Setter
@NoArgsConstructor
@EqualsAndHashCode
@ToString
public class Subsidy {
private String country;
private String category;
private int familyCount;
}
@Test
public void ๋ณด์กฐ๊ธ์ง๊ธ() {
Subsidy ์ฒซ๋ฒ์งธ๊ฐ๊ตฌ = new Subsidy();
์ฒซ๋ฒ์งธ๊ฐ๊ตฌ.setCountry("ํ๊ตญ");
์ฒซ๋ฒ์งธ๊ฐ๊ตฌ.setCategory("๊ทผ๋ก์ฅ๋ ค๊ธ");
์ฒซ๋ฒ์งธ๊ฐ๊ตฌ.setFamilyCount(1);
System.out.println("์ฒซ๋ฒ์งธ๊ฐ๊ตฌ : " + ์ฒซ๋ฒ์งธ๊ฐ๊ตฌ);
// ์ฒซ๋ฒ์งธ๊ฐ๊ตฌ = (country=ํ๊ตญ, category=๊ทผ๋ก์ฅ๋ ค๊ธ, familyCount=1)
Subsidy ๋๋ฒ์งธ๊ฐ๊ตฌ = ์ฒซ๋ฒ์งธ๊ฐ๊ตฌ;
System.out.println("๋๋ฒ์งธ๊ฐ๊ตฌ : " + ๋๋ฒ์งธ๊ฐ๊ตฌ);
// ๋๋ฒ์งธ๊ฐ๊ตฌ = (country=ํ๊ตญ, category=๊ทผ๋ก์ฅ๋ ค๊ธ, familyCount=1)
๋๋ฒ์งธ๊ฐ๊ตฌ.setCategory("์๋
์ฅ๋ ค๊ธ");
๋๋ฒ์งธ๊ฐ๊ตฌ.setFamilyCount(4);
System.out.println("์ฒซ๋ฒ์งธ๊ฐ๊ตฌ : " + ์ฒซ๋ฒ์งธ๊ฐ๊ตฌ);
System.out.println("๋๋ฒ์งธ๊ฐ๊ตฌ : " + ๋๋ฒ์งธ๊ฐ๊ตฌ);
// ์ฒซ๋ฒ์งธ๊ฐ๊ตฌ = (country=ํ๊ตญ, category=์๋
์ฅ๋ ค๊ธ, familyCount=4)
// ๋๋ฒ์งธ๊ฐ๊ตฌ = (country=ํ๊ตญ, category=์๋
์ฅ๋ ค๊ธ, familyCount=4)
}
Lombok ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ์ต๋๋ค.
โ๏ธ๊ตญ๊ฐ์ ๋ณด์กฐ๊ธ์ ์ ํ๋ ๊ตญ๊ฐ์ด๋ฆ, ๋ณด์กฐ๊ธ ๋ฒ์ฃผ, ๊ฐ์กฑ ์๋ฅผ ๊ฐ์ผ๋ก ๊ฐ๋ Subsidy ๋ผ๋ VO๋ฅผ ๋ง๋ค์์ต๋๋ค.
ย ย ย ย ย ๋ ๊ฐ๊ตฌ์ ๋ณด์กฐ๊ธ ์ ์ฒญ์ด ๋ค์ด์๊ณ , ๊ฐ์ 1์ธ๊ฐ๊ตฌ ๊ทผ๋ก์ฅ๋ ค๊ธ์ ์ ์ฒญํ์ฌ ๊ฐ์ฒด๋ฅผ ๋ณต์ฌํด์ ์ฌ์ฉํ์ต๋๋ค.
ย ย ย ย ย ์ด์ฐจํผ ๊ฐ์ ๋ณด์กฐ๊ธ์ด๊ณ ๊ฐ์กฑ ์๊ฐ ๊ฐ์ผ๋ ๋ฌธ์ ๋ ๊ฒ ์๋ค๊ณ ์๊ฐํ์ต๋๋ค.
๐งจ๊ทธ๋ฐ๋ฐ ์ด ๋, ๋ ๋ฒ์งธ ๊ฐ๊ตฌ์ ์ฌ์ฌ ๊ฒฐ๊ณผ๊ฐ 4์ธ๊ฐ๊ตฌ์ ์๋ ์ฅ๋ ค๊ธ ๋์์๋ก ๋์์ต๋๋ค.
ย ย ย ย ย ๋ถ๋ช ๋ ๋ฒ์งธ ๊ฐ๊ตฌ์ ๋ด์ฉ๋ง ๋ณ๊ฒฝํ์ ๋ฟ์ธ๋ฐ, ์ถ๋ ฅ๋ ๊ฒฐ๊ณผ๋ฅผ ์ดํด๋ณด๋ฉด,
ย ย ย ย ย ์ฒซ ๋ฒ์งธ ๊ฐ๊ตฌ๊น์ง 4์ธ ๊ฐ๊ตฌ ์๋ ์ฅ๋ ค๊ธ์ผ๋ก ๋ณด์กฐ๊ธ์ด ๋ณ๊ฒฝ๋์์ต๋๋ค.
๐๋ฌธ์ ์ ์์์ ์ฌ์ฉํ ๊ฐ์ด ๊ฐ๋ค๊ณ ํด์ ์ฒซ ๋ฒ์งธ ๊ฐ๊ตฌ ๊ฐ์ ๋ ๋ฒ์งธ ๊ฐ๊ตฌ์ ๊ทธ๋๋ก ๋ณต์ฌํ ๊ณณ ์ ๋๋ค.
ย ย ย ย ย ํ์ฌ ๋ ๋ฒ์งธ ๊ฐ๊ตฌ๋ ์ฒซ ๋ฒ์งธ ๊ฐ๊ตฌ ๊ฐ์ ๋ณต์ฌํ ๊ฒ์ด ์๋ ์ฐธ์กฐํ๊ณ ์๋ ๋ฉ๋ชจ๋ฆฌ ์ฃผ์๋ฅผ ๋ณต์ฌํ๊ธฐ ๋๋ฌธ์
ย ย ย ย ย ๋ณด์กฐ๊ธ ๋ด์ฉ์ด ๋ฐ๋๋ฉด ๋ฉ๋ชจ๋ฆฌ ์์ ์ ์ฅ๋ ์ค์ ๊ฐ์ด ๋ณ๊ฒฝ๋ฉ๋๋ค.
ย ย ย ย ย ๋น์ฐํ ๊ฐ์ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ์ฐธ์กฐํ๊ณ ์๋ ์ฒซ ๋ฒ์งธ ๊ฐ๊ตฌ์ ๋ด์ฉ๋ ๋ณ๊ฒฝ๋ ๊ฐ์ ๊ฐ๋ฆฌํค๊ฒ ๋๋ ๊ฒ ์ ๋๋ค.
์ด๋ฌํ ์น๋ช
์ ์ธ ์ค๋ฅ๋ฅผ ๋ฐฉ์งํ๊ธฐ ์ํด์ VO๋ ํ๋ฒ ์ค์ ๋ ๊ฐ์ด ๋ณํ์ง ์๋๋ก ํด์ผ ํฉ๋๋ค.
์ฆ, ๊ฐ์ ๋ณ๊ฒฝํ ์ ์๋ ์์ ์(Setter)๊ฐ ์์ด์ผ ํฉ๋๋ค.
๊ทธ๋ผ ์์ ์ ์์ด ์ด๋ป๊ฒ VO์ ๊ฐ์ ์ค์ ํ ๊น์?
์์ฑ์๋ฅผ ํตํด ๊ฐ์ฒด๊ฐ ์์ฑ๋ ๋, ๊ฐ์ด ํ ๋ฒ๋ง ํ ๋น๋๊ณ ์ดํ๋ก๋ ๋ณ๊ฒฝ๋์ง ์๋๋ก ๋ง๋ค ์ ์์ต๋๋ค.
์์ฑ์๋ฅผ ํตํด์ Subsidy ๊ฐ์ฒด๋ฅผ ๋ถ๋ณ(Immutable)๋ก ๋ง๋ค๋ฉด ์์ ๊ฐ์ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ์ ์์ต๋๋ค.
๊ทธ๋ ๋ค๋ฉด ๋ถ๋ณ ๊ฐ์ฒด๋ฅผ ๋ง๋ค์ด ๋ด ์๋ค.
@Getter
@AllArgsConstructor
@EqualsAndHashCode
@ToString
public class Subsidy {
private String country;
private String category;
private int familyCount;
}
@Test
public void ๋ณด์กฐ๊ธ์ง๊ธ() {
Subsidy ์ฒซ๋ฒ์งธ๊ฐ๊ตฌ = new Subsidy("ํ๊ตญ", "๊ทผ๋ก์ฅ๋ ค๊ธ", 1);
System.out.println("์ฒซ๋ฒ์งธ ๊ฐ๊ตฌ : " + ์ฒซ๋ฒ์งธ๊ฐ๊ตฌ);
// ์ฒซ๋ฒ์งธ๊ฐ๊ตฌ = (country=ํ๊ตญ, category=๊ทผ๋ก์ฅ๋ ค๊ธ, familyCount=1)
Subsidy ๋๋ฒ์งธ๊ฐ๊ตฌ = new Subsidy("ํ๊ตญ", "๊ทผ๋ก์ฅ๋ ค๊ธ", 1);
System.out.println("๋๋ฒ์งธ ๊ฐ๊ตฌ : " + ๋๋ฒ์งธ๊ฐ๊ตฌ);
// ๋๋ฒ์งธ๊ฐ๊ตฌ = (country=ํ๊ตญ, category=๊ทผ๋ก์ฅ๋ ค๊ธ, familyCount=1)
// ์ฌ์ฌ๋ก ์ธํ ๋๋ฒ์งธ๊ฐ๊ตฌ ๋ณด์กฐ๊ธ ๋ณ๊ฒฝ
๋๋ฒ์งธ๊ฐ๊ตฌ = new Subsidy("ํ๊ตญ", "์๋
์ฅ๋ ค๊ธ", 4);
System.out.println("์ฒซ๋ฒ์งธ ๊ฐ๊ตฌ : " + ์ฒซ๋ฒ์งธ๊ฐ๊ตฌ);
System.out.println("๋๋ฒ์งธ ๊ฐ๊ตฌ : " + ๋๋ฒ์งธ๊ฐ๊ตฌ);
// ์ฒซ๋ฒ์งธ๊ฐ๊ตฌ = (country=ํ๊ตญ, category=๊ทผ๋ก์ฅ๋ ค๊ธ, familyCount=1)
// ๋๋ฒ์งธ๊ฐ๊ตฌ = (country=ํ๊ตญ, category=์๋
์ฅ๋ ค๊ธ, familyCount=4)
}
์์ ์(Setter)๋ฅผ ์ ๊ฑฐํ์ผ๋ฏ๋ก ์ฌ์ฌ๋ก ์ธํด ๋ณด์กฐ๊ธ์ด ๋ณ๊ฒฝ๋๋ค๋ฉด,
์์ฑ์๋ฅผ ํตํด ๊ฐ์ฒด๋ฅผ ์๋ก ์์ฑํ๊ณ ์ฌํ ๋น ํด์ฃผ์ด์ผํฉ๋๋ค.
์ด๋ ๊ฒ ํ๋ฉด ์์ฑ ๊ฐ ์์ฒด๊ฐ ์๋ณ ๊ฐ์ ์ญํ ์ ํ๋ VO์ ์ ์ฒด์ฑ์ ์งํค๋ฉด์,
๋ฌด์๋ณด๋ค๋ ์๋์น ์์ ๋ณ๊ฒฝ์ ๋ง์ ์ ์๊ธฐ ๋๋ฌธ์ ์ ์ง๋ณด์์๋ ํจ๊ณผ์ ์
๋๋ค.
VO๋ผ๋ ๊ฐ์ฒด๋ฅผ ์ฌ์ฉํ์ง ์๊ณ ๋ ์ถฉ๋ถํ ์์ ํ์
์ ๊ฐ๋ง ๊ฐ์ง๊ณ ํ๋ก๊ทธ๋๋ฐ์ ํ ์ ์์ต๋๋ค.
ํ์ง๋ง VO๋ฅผ ํตํด ๋๋ฉ์ธ์ ์ค๊ณํ๋ค๋ฉด, ๊ฐ์ฒด๊ฐ ์์ฑ๋ ๋ ํด๋น ๊ฐ์ฒด์์ ์ ์ฝ์ฌํญ์ ์ถ๊ฐํ ์ ์์ต๋๋ค.
๋ํ ์์ฑ๋ ์ธ์คํด์ค๊ฐ ์ ํด์ ธ ์๋ ๊ฒฝ์ฐ์๋ ๋ฏธ๋ฆฌ ์ธ์คํด์ค๋ฅผ ์์ฑํด๋๊ณ
์บ์ฑํ์ฌ ์ฑ๋ฅ์ ๋์ด๋ ๋ฐฉ๋ฒ๋ ๊ณ ๋ คํด๋ณผ ์ ์์ต๋๋ค.
๊ทธ๋ฟ๋ง ์๋๋ผ, Entity์ ์์ ๊ฐ๋ค์ VO๋ก ํฌ์ฅํ๋ฉด
Entity๊ฐ ์ง๋์น๊ฒ ๊ฑฐ๋ํด์ง๋ ๊ฒ์ ๋ง์ ์ ์์ด์,
ํ
์ด๋ธ ๊ด์ ์ด ์๋ ๊ฐ์ฒด ์งํฅ์ ์ธ ๊ด์ ์ผ๋ก ํ๋ก๊ทธ๋๋ฐํ ์ ์์ต๋๋ค.
์ปฌ๋ ์ ๋ VO์ ์ญํ ์ ํ๋ค๋ฉด, ์ผ๊ธ ์ปฌ๋ ์ ๊ณผ ๊ฐ์ ๋ถ๋ณ๊ฐ์ฒด๋ก ๋ง๋ค์ด์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
๊ทธ๋ ๋ค๋ฉด DTO๋ ๋ฌด์์ผ๊น์?
Martin Fowler์ ๊ธ์ ์ฝ์ด๋ณด๊ฒ ์ต๋๋ค.
โ๐ผAn object that carries data between processes in order to reduce the number of method calls.
๐๋ฉ์๋ ํธ์ถ ์๋ฅผ ์ค์ด๊ธฐ ์ํด ํ๋ก์ธ์ค ๊ฐ์ ๋ฐ์ดํฐ๋ฅผ ์ ์กํ๋ ๊ฐ์ฒด
โ๐ผAlthough the main reason for using a Data Transfer Object is to batch up what would be multiple
ย ย ย ย ย remote calls into a single call, it's worth mentioning that another advantage is to encapsulate the
ย ย ย ย ย serialization mechanism for transferring data over the wire. By encapsulating the serialization
ย ย ย ย ย like this, the DTOs keep this logic out of the rest of the code and also provide a clear point to
ย ย ย ย ย change serialization should you wish.
๐๋ฐ์ดํฐ ์ ์ก ๊ฐ์ฒด๋ฅผ ์ฌ์ฉํ๋ ์ฃผ๋ ์ด์ ๋ ์ฌ๋ฌ ์๊ฒฉ ํธ์ถ์ ๋จ์ผ ํธ์ถ๋ก ์ผ๊ด ์ฒ๋ฆฌํ๋ ๊ฒ์ด๋ฏ๋ก
ย ย ย ย ย ์ ์ ์ ํตํด ๋ฐ์ดํฐ๋ฅผ ์ ์กํ๊ธฐ์ํ ์ง๋ ฌํ ๋ฉ์ปค๋์ฆ์ ์บก์ํํ๋ ๊ฒ์ด ๋ ๋ค๋ฅธ ์ฅ์ ์ ๋๋ค.
ย ย ย ย ย ์ด์ ๊ฐ์ด ์ง๋ ฌํ๋ฅผ ์บก์ํํจ์ผ๋ก์จ DTO๋ ์ด ๋ ผ๋ฆฌ๋ฅผ ๋๋จธ์ง ์ฝ๋์์ ์ ์ธํ๊ณ ์ํ๋ ๊ฒฝ์ฐ
ย ย ย ย ย ์ง๋ ฌํ๋ฅผ ๋ณ๊ฒฝํ ์์๋ ๋ช ํํ ์ง์ ์ ์ ๊ณตํฉ๋๋ค.
๊ธ ์์ฝ์์ต๋๋ค. VO์ ๋ถ๋ณ๊ฐ์ฒด๋ก ๋ง๋ค์ด์ง๋ ์ด์ ์ค ์ถ์ ์ด ๋ถ๊ฐ๋ฅํ ์ ์ ๋ค์ด์ฃผ์ จ๋๋ฐ ์ถ์ ์ด ๋ถ๊ฐ๋ฅํ ๊ฒ๊ณผ ๋ถ๋ณ์ ์ด๋ค ๊ด๊ณ๊ฐ ์๋ ์ง ์ดํด๊ฐ ์๊ฐ์ ์์๋ก ์ค๋ช ๊ฐ๋ฅํ ๊น์?