개발자꿈나무
값 타입과 불변 객체 본문
값 타입이라는 건 복잡한 객체 세상을 조금이라도 단순화하기 위해 만들어진 개념으로 단순하고 안전하게 부작용 없이 사용할 수 있어야 한다.
★ 값 타입 공유 참조
- 임베디드 값 타입처럼 값 타입을 여러 엔티티에서 공유하면 부작용이 발생할 수 있다.
Address address = new Address("seoul", "street", "1000");
Member member1 = new Member();
member1.setName("member1");
member1.setHomeAddress(address);
em.persist(member1);
Member member2 = new Member();
member2.setName("member2");
member2.setHomeAddress(address);
em.persist(member2);
member1.getHomeAddress().setCity("busan");
새로운 address 객체를 생성하고 member1과 member2에 setHomeAddress를 같은 객체를 넣어준 후 member1의 도시를 부산으로 변경해주면 어떤 결과가 나오게 될까?
member1만 부산으로 변경되기를 바랬지만 데이터베이스를 조회해보면 member2도 부산으로 바뀐 모습을 확인할 수 있다. 실제 update 쿼리도 2번 나가게 된다. 이는 임베디드 값 타입이 참조를 공유하기 때문이다. 그렇기 때문에 임베디드 값 타입을 여러 엔티티에서 사용하려면 꼭 값을 복사해줘야 한다!
Address address = new Address("seoul", "street", "1000");
Member member1 = new Member();
member1.setName("member1");
member1.setHomeAddress(address);
em.persist(member1);
Address copyAddress = new Address(address.getCity(), address.getStreet(), address.getZipcode()); //카피
Member member2 = new Member();
member2.setName("member2");
member2.setHomeAddress(copyAddress);
em.persist(member2);
member1.getHomeAddress().setCity("busan");
이렇게 copyAddress를 새로 생성해서 address의 값들을 불러오고 address를 수정하게 되면 copyAddress와 address는 서로 다른 참조를 가지므로 영향을 받지 않고 member1의 도시만 수정할 수 있게 된다.
★ 객체 타입의 한계
- 항상 값을 복사해서 사용하면 공유 참조로 인해 발생하는 부작용을 피할 수 있다.
- 하지만 임베디드 타입은 자바의 기본 타입이 아니라 객체 타입이므로 참조 값을 직접 대입하는 방법을 막을 수 없다.
-> 값이라는건 부작용에 대한 걱정없이 언제나 안전하게 사용할 수 있어야 하는데 이 경우는 직접 복사를 해줘야 하며, 혹시라도 발생할 불상사를 대비해야 한다는 것이다. 실제로 자바의 기본 타입은 직접 대입을 할 때 무조건 값을 복사하므로 우리가 자바를 사용할 때 한번도 이러한 부작용에 대해서 걱정해본 적이 없을 것이다. - 객체의 공유 참조는 피할 수 없다.
★ 불변 객체 (immutable object) : 생성 시점 이후 절대로 값을 변경할 수 없는 객체
이러한 한계를 예방하기 위해서는 애초에 객체 타입을 수정할 수 없도록 부작용을 원천 차단해버리는 것이다. 이전 기본 값 타입에 대해 정리할 때 자바의 래퍼 객체나 String 같은 특수한 객체에 대해 이야기한 적이 있는데 공유가 가능하지만 변경이 되지 않는다고 정리했었다. (대표적인 불변 객체) 이처럼 임베디드 값 타입도 불변 객체로 만들어버리는 것이다.
불변 객체로 만드는 방법은 여러가지가 있지만 가장 간단한 방법이 생성자를 통해 객체를 생성만 하고, 수정을 불가능하게 만드는 것이다
-> setter 자체를 없애버리거나 private 으로 만들어버리면 된다.
Address address = new Address("seoul", "street", "1000");
Member member1 = new Member();
member1.setName("member1");
member1.setHomeAddress(address);
em.persist(member1);
Address newAddress = new Address("busan", address.getStreet(), address.getZipcode());
Member member2 = new Member();
member2.setName("member1");
member2.setHomeAddress(address);
em.persist(member2);
member1.setHomeAddress(newAddress);
그러면 더이상 setCity()를 할 수 없고, 부작용이 생길 위험을 원천봉쇄해버리는 것이다.
'자바 > JPA' 카테고리의 다른 글
객체지향 쿼리 언어 (0) | 2023.08.29 |
---|---|
값 타입 컬렉션 (0) | 2023.08.28 |
갑 타입 - 임베디드 타입 (0) | 2023.08.23 |
값 타입 - 기본 값 (0) | 2023.08.23 |
영속성 전이, 고아 객체 (0) | 2023.08.22 |