[JPA] 값 타입과 불변 객체
값 타입이란?
String, int와 같은 특정 값을 저장하는 타입
- 복잡한 객체 세상을 조금이라도 단순화하려고 만든 개념으로, 단순하고 안전하게 다룰 수 있어야한다.
값 타입 공유 참조
- 임베디드 타입같은 값 타입을 여러 엔티티에서 공유할 수 있다.
- 단, 여러 엔티티에서 공유하는 경우 하나의 엔티티에서 값을 변경하면
의도치않게 함께 공유했었던 엔티티에서의 값도 변하는 부작용(side effect)이 발생할 수 있다.
Address address = new Address("city", "strett", "10000");
Member member = new Member();
member.setUsername("member1");
member.setHomeAddress(address);
em.persist(member);
Member member2 = new Member();
member.setUsername("member2");
member.setHomeAddress(address);
em.persist(member2);
member.getHomeAddress().setCity("newCity");
tx.commit();
위 코드에서 개발자는 member에 있는 주소값만 변경해주려고 했으나,
member2의 주소값까지 변경된다.(side effect 발생)
따라서 대신 값(인스턴스)을 복사해서 사용해야한다.
Address address = new Address("city", "strett", "10000");
Member member = new Member();
member.setUsername("member1");
member.setHomeAddress(address);
em.persist(member);
Address copyAaddress = new Address(address.getCity(), address.getStreet(), address.getZipcode());
Member member2 = new Member();
member.setUsername("member2");
member.setHomeAddress(copyAaddress);
em.persist(member2);
member.getHomeAddress().setCity("newCity");
tx.commit();
위 코드처럼 값을 복사해서 사용하면 member의 주소를 newCity로 변경해도 member2의 주소는 변하지 않는다.
객체 타입의 한계
자바 기본 타입은 값을 대입하면 값을 복사하지만,
자바 객체 타입은 참조값을 값을 복사하지않고 직접 대입하며 이를 막을 방법이 없다.
문제는 임베디드 타입처럼 직접 정의한 값 타입도 객체타입으로,
위의 코드처럼 직접적으로 항상 값을 복사해서 사용하지 않는 이상 공유 참조로 인한 부작용을 피할 수 없다.
int a = 5;
int b = a; // 기본 타입은 값을 복사하여 저장
b = 4; // 이래도 a는 여전히 5
Address a = new City("Seoul");
Address b = a; // 객체 타입은 참조를 전달
b.setCity("Busan"); // a도 Busan이 됨
불변 객체
: 객체 타입의 부작용을 원천 차단하기 위해 수정할 수 없게 만든 객체이다.
- 생성자로만 값을 설정하고 setter와 같은 수정자를 만들지 않아
생성 시점 이후 절대 값을 변경할 수 없는 객체이다.(Integer, String은 자바의 대표적 불변 객체)
-> 불변이라는 제약으로 부작용이라는 큰 문제를 막을 수 있다.
하지만 그럼에도 불구하고 불변 객체에서 값을 변경하고 싶다면?
Address address = new Address("city", "strett", "10000");
Member member = new Member();
member.setUsername("member1");
member.setHomeAddress(address);
em.persist(member);
Address newAaddress = new Address(address.getCity(), address.getStreet(), address.getZipcode());
Member member = new Member();
member.setHomeAddress(newAaddress);
tx.commit();
위 코드는 Address가 불변객체인 상황인데 수정한 모습이다.
불변 객체는 생성자를 통해 새로운 객체를 만든 뒤, member 객체에 주입해줘야만 객체 수정이 가능하다.