넓은 범위에서 쓰이는 데이터에 직접 접근하지 못하게 하고, 읽고 쓰는 함수를 통해서만 다루게 하는 리팩터링. 데이터를 옮기거나 바꿀 때 고쳐야 할 곳이 접근 함수 한 곳으로 좁아진다.
let defaultOwnerData = { firstName: '마틴', lastName: '파울러' }
export const defaultOwner = () => ({ ...defaultOwnerData }) // 복제본을 준다
export const setDefaultOwner = (arg: typeof defaultOwnerData) => { defaultOwnerData = arg }- 전역 데이터(Global Data)·가변 데이터(Mutable Data) 냄새의 첫 처방이다. 누가 언제 값을 바꾸는지 감시할 통로가 생기고, 바꾸기 전 검증도 끼워 넣을 수 있다
- 레코드 캡슐화(Encapsulate Record): 객체 리터럴을 클래스로 감싸면 저장된 값과 계산된 값을 구분할 필요가 없어지고, 이름을 바꿀 때 옛 이름과 새 이름을 함께 제공할 수 있다
- 컬렉션 캡슐화(Encapsulate Collection): 게터가 내부 배열을 그대로 내주면 밖에서 몰래 원소를 바꿀 수 있다. 복제본을 돌려주고
add·remove같은 변경 메서드를 따로 둔다. 불필요한 복제가 예상치 못한 수정을 디버깅하는 것보다 싸다 - 복제할 때 중첩 객체까지 복사되는지는 얕은 복사와 깊은 복사 참고
- 바뀌면 안 되는 필드는 세터를 아예 없애 불변으로 만든다. 그 끝에는 값 객체가 있다
React에서 상태를 직접 바꾸지 않고 새 객체로 교체하는 규칙(React 상태 갱신)도 같은 문제의식에서 나온다.
출처: 『리팩터링 2판』 마틴 파울러 (원서 Refactoring, 2nd Edition) · refactoring.com: Encapsulate Variable · refactoring.com: Encapsulate Record · refactoring.com: Encapsulate Collection · Refactoring.Guru: Encapsulate Field