p.329 데이터 구조 리팩터링.
하나의 값이 여러 목적으로 사용된다면 혼란과 버그를 낳는다. 그러니 이런 코드를 발견하면 변수 쪼개기를 적용해 용도별로 분리하자. 한편, 파생변수를 질의함수로 바꾸기를 활용하여 변수 자체를 완전히 없애는 게 가장 좋은 해법일 때도 있다.
p.330 변수 쪼개기
for loop문에 있는 변수 i는 반복문을 한번 돌때마다 값이 바뀐다. 수집 변수는 메서드가 동작하는 중간중간 값을 저장한다. 그 외에도 변수는 긴 코드의 결과를 저장했다가 나중에 쉽게 참조하려는 목적으로 흔히 쓰인다. 이런 변수에는 값을 단 한번만 대입해야한다. 대입이 두번 이상 이뤄진다면 여러가지 역할을 수행한다는 신호다. 역할이 둘 이상인 변수가 있다면 쪼개야된다.
p.338 파생 변수를 질의 함수로 바꾸기
가변 데이터는 소프트웨어
p.343 참조를 값으로 바꾸기
객체를 다른 객체에 중첩하면 내부 객체를 참조 혹은 값으로 취급할 수 있다. 참조냐 값이냐의 차이는 내부 객체의 속성을 갱신하는 방식에서 가장 극명하게 드러난다. 참조로 다루는 경우에는 내부 객체는 그대로 둔 채 그 객체의 속성만 갱신하며, 값으로 다루는 경우에는 새로운 속성을 담은 객체로 기존 내부 객체를 통째로 대체한다. 필드를 값으로 다룬다면 내부 객체의 클래스를 수정하여 값 객체로 만들 수있다. 값 객체는 대체로 자유롭게 활용하기 좋은데, 특히 불변이기 때문이다.일반적으로 불변 데이터 구조는 다루기 더 쉽다. 불변 데이터 값은 프로그램 외부로 건네줘도 나중에 그 값이 나 몰래 바뀌어서 내부에 영향을 줄까 염려하지 않아도 된다. 값을 복제해 이곳 저곳에서 사용하더라도 서로 간의 참조를 관리하지 않아도 된다. 그래서 값 객체는 분산 시스템과 동시성 시스템에서 특히 유용하다. 한편 값 객체의 이런 특성 떄문에 이번 리팩터링을 적용하면 안 되는 상황도 있다. 예컨대 특정 객체를 열 객체에서 공유하고자 한다면, 그래서 공유 객체의 값을 변경했을 떄 이를 관련 객체 모두에 알려줘야 한다면 공유 객체를 참조로 다뤄야 한다.
기존 코드
Person class
1
2
3
4
5
6
7
8
9
class Person{
constructor(){
this._telephoneNumber = new TelephoneNumber();
}
get officeAreaCode(){return this._telephoneNumber.areaCode;}
set officeAreaCode(arg){this._telephoneNumber.areaCode = arg;}
get officeNumber(){return this._telephoneNumber.number;}
set officeNumber(arg){this._telephoneNumber.number = arg;}
}
추출해서 새로 만들어진 객체(TelephoneNumber)를 갱신하는 메서드 들은 여전히 추출 전 클래스(Person)에 존재할 것이다. 어쨌든 새 클래스가 가리키는 참조가 하나뿐이므로 참조를 값으로 바꾸기에 좋은 상황.
TelephoneNumber class
1
2
3
4
5
6
7
class TelephoneNumber{
...
get areaCode(){return this._areaCode;}
set areaCode(arg){this._areaCode = arg;}
get number(){return this._number;}
set number(arg){this._number = arg;}
}
수정된 코드
Person class
1
2
3
4
5
6
7
8
9
10
11
12
13
class Person{
constructor(){
this._telephoneNumber = new TelephoneNumber();
}
get officeAreaCode(){return this._telephoneNumber.areaCode;}
set officeAreaCode(arg){
this._telephoneNumber = new TelephoneNumber(arg, this.officeNumber);
}
get officeNumber(){return this._telephoneNumber.number;}
set officeNumber(arg){
this._telephoneNumber = new TelephoneNumber(this.officeAreaCode,arg);
}
}
먼저 전화번호를 불변으로 만든다. 필드들의 세터들만 제거하면 된다. 세터 제거의 첫 단계로 세터로 설정하던 두 필드를 생성자에서 입력받아 설정하도록 한다.
TelephoneNumber class
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class TelephoneNumber{
constructor(areaCode,number){
this._areaCode = areaCode;
this._number = number;
}
get areaCode(){return this._areaCode;}
set areaCode(arg){this._areaCode = arg;}
get number(){return this._number;}
set number(arg){this._number = arg;}
equals(other){
if(!(other instanceof TelephoneNumber)) return false;
return this.areaCode === other.areaCode && this.number === other.number;
}
}
대부분의 객체지향 언어는 값 기반 동치성 비교를 할 수 있도록 오버라이드 가능한 동치성 검사 수단을 제공한다. 하지만 JS는 참조기반 동치성을 값 기반 동치성으로 대체하는 일과 관련하여 언어나 핵심 라이브러리 차원에서 지원해주는게 없기 때문에 임의로 equals() 작성
Comments powered by Disqus.