티스토리 뷰

반응형

마틴 파울러 - 리팩터링 (2판) 의  9장 내용 중 기억하고 싶은 것 기록 ✏️✏️


 

9.4 참조를 값으로 바꾸기 (change Reference to Value)

 

 

- 참조로 다루는 경우: 내부 객체는 그대로 둔 채 그 객체의 속성산 갱신함.

- 값으로 다루는 경우: 새로운 속성을 담은 객체로 기존 내부 객체를 통째로 대체함

 

값 객체는 불변이기 때문에 자유롭게 활용하기 쉽다. 

불변 데이터 값은 프로그램 외부로 건네줘도 나중에 그 값이 나 몰래 바뀌어서 내부에 영향을 줄까 염려하지 않아도 된다.

값을 복제해 이곳저곳에서 사용하더라도 서로간의 참조를 관리하지 않아도 된다.

그래서 값 객체는 분산 시스템, 동시성 시스템에서 특히 유용하다.

 

9.5에서 나오지만..

이런 값 객체의 특성 때문에 이번 리팩터링을 적용하면 안되는 상황도 있다. 

예컨대 특정 객체를 여러 객체에서 공유하고자 한다면, 그래서 공유 객체의 변경했을 때 이를 관련된 객체 모두에게 알려줘야한다면

공유 객체를 참조로 다뤄야한다. 

 

[ 리팩터링 절차 ]

 

1. 후보 클래스가 불변이 될 수 있는 지 확인한다.

2. 각각의 세터를 하나씩 제거한다.

3. 값 객체의 필드들을 사용하는 동치성(equaility) 비교 메소드를 만든다. 

 

 

[ 예시 ]

 

telephoneNumber를 들고 있는 Person 클래스를 예시로 살펴보자. 

 

 

1. 가장 먼저 할 일은 전화번호를 불변으로 만들기다.

 

2. 필드들의 세터들만 제거하면 된다. 

세터 제거의 첫 단계로, 세터로 설정하던 두 필드를 생성자에서 입력받아 설정하도록 하고 

 

 

세터를 호출하는 쪽에서 전화번호를 매번 다시 만들어서 대입하도록 바꿔준다. 

 

 

 

3. 이제 전화번호는 불변이 되었고 값 객체로 인정받기 위해 동치성 비교를 통과해야한다. 

 

 

 

9.5 값을 참조로 바꾸기 (Change Value to Reference) 

 

 

주문 목록을 생각해보자. 주문 목록을 읽다보면 같은 고객이 요청한 주문이 여러개 섞여있을 수 있다.

이때 고객을 값으로도, 혹은 참조로도 다룰 수 있다.

값으로 다룬다면 고객데이터가 각 주문에 복사되고, 참조로 다룬다면 여러 주문이 단 하나의 데이터 구조를 참조하게 된다. 

 

고객 데이터를 갱신할 일이 없다면 어느 방식이든 상관없다.

하지만 논리적으로 같은 데이터를 물리적으로 복제해 사용할 때 가장 크게 문제되는 상황은 그 데이터를 갱신해야할 때다.

모든 복제본을 찾아서 빠짐없이 갱신해야하며, 하나라도 놓치면 데이터 일관성이 깨져버린다.

 

이런 상황이라면 복제된 데이터들을 모두 참조로 바꿔주는 게 좋다. 

데이터가 하나면 갱신된 내용이 해당 고객의 주문 모두에 곧바로 반영되기 때문이다. 

 

값을 참조로 바꾸면 entity 하나당 객체도 단 하나만 존재하게 되는데, 그러면 보통 이런 객체들을 한데 모아놓고 클라이언트들의 접근을 관리해주는 일종의 저장소가 필요해진다.

각 entity를 표현하는 객체를 한 번만 만들고, 객체가 필요한 곳에서는 모두 이 저장소로부터 얻어 쓰는 방식이 된다.

 

 

[ 리팩터링 절차 ]

 

1. 같은 부류에 속하는 객체들을 보관할 저장소를 만든다. (이미 있다면 생략)

2. 생성자에서 이 부류의 객체들 중 특정 객체를 정확하게 찾아내는 방법이 있는지 확인한다.

3. 호스트 객체의 생성자들을 수정하여 필요한 객체를 이 저장소에서 찾도록 한다. 하나 수정할 때마다 테스트한다. 

 

[ 예시 ]

 

주문(Order) 클래스를 예시로 보자.

이 클래스는 생성자에서 주문 데이터(JSON 문서)를 입력받아 필드들을 채운다.

이 과정에서 주문 데이터에 포함된 고객 ID를 사용해 고객(Customer) 객체를 생성한다. 

 

 

이런 방식으로 생성한 고객 객체는 값이다.

고객 ID가 123인 주문을 다섯 개 생성한다면 독립된 고객 객체가 다섯개 만들어진다.

이 중 하나를 수정하더라도 나머지 네 개에는 반영되지 않는다. 

 

이제 값을 참조로 바꾸는 리팩터링을 시작해보자!

 

1. 항상 물리적으로 똑같은 고객 객체를 사용하고 싶다면 먼저 이 유일한 객체를 저장해둘 곳이 있어야한다. 

 

저장소 객체 (repository object)를 만든다. 

이 저장소는 고객 객체를 ID와 함께 등록할 수 있으며, ID 하나당 오직 하나의 고객 객체만 생성됨을 보장한다. 

 

 

 

2. 주문의 생성자에서 올바른 고객 객체를 얻어오는 방법을 찾는다. 

이번 예에서는 고객 ID가 입력 데이터로 들어오니까 쉽게 해결할 수 있다.

 

3. Order 클래스의 생성자을 수정하자. 고객을 이 저장소에서 찾도록 한다. 

 

 

 

이제 특정 주문과 관련된 고객 정보를 갱신하면

같은 고객을 공유하는 주문 모두에서 갱신된 고객 데이터를 사용하게 된다. 

 

 

 

반응형
댓글