모듈을 분리하는 가장 중요한 기준은 시스템에서 각 모듈이 자신을 제외한 다른 부분에 드러내지 않아야 할 비밀을 얼마나 잘 숨기느냐에 있을 것이다.
7장에 나오는 리팩터링 기법들
- 대표적 형태의 데이터구조: 레코드 캡슐화, 컬렉션 캡슐화
- 기본형 데이터의 경우: 기본형을 객체로 바꾸기
- 정확한 순서로 계산이 필요할 때: 임시 변수를 질의 함수로 바꾸기
- 추출/인라인하기의 클래스 버전: 클래스 추출하기, 클래스 인라인하기
- 클래스 연결 관계를 은닉: 위임숨기기
- 위임 숨기기의 반대기법: 중개자 제거하기
- 함수도 구현을 캡슐화할 때: 함수 추출하기, 알고리즘 교체하기
// before
organization = {name: "애크미 구스베리", country: "GB"}
// after
class Organization {
constructor(data) {
this._name = data.name;
this._country = data.country;
}
get name() {return this._name;}
set name(arg) {this._name = arg;}
get country() {return this._country;}
set country(arg) {this._country = arg;}
// before
class Person {
get courses() {return this._courses;}
set courses(aList) {this._courses = aList;}
}
// after
class Person {
get courses() {return this._courses.slice()}
addCourse(aCourse) {}
removeCourse(aCourse) {}
}
// before
orders.filter(o => "high" === o.priority || "rush" === o.priority)
// after
orders.filter(o => o.priority.higherTahn(new Priority("normal")))
// before
const basePrice = this._quantity * this._itemPrice;
if (basePrice > 1000) {
return basePrice * 0.95;
} else {
return basePrice * 0.98;
}
// after
get basePrice() {this._quantity * this._itemPrice;}
if (this.basePrice > 1000) {
return this.basePrice * 0.95;
} else {
return this.basePrice * 0.98;
}
// before
class Person {
get officeAreaCode() {return this._officeAreaCode;}
get officeNumber() {return this._officeNumber;}
}
// after
class Person {
constructor() {
this._telephonNumber = new TelephoneNumber()
}
get officeAreaCode() {return this._telephonNumber.areaCode;}
get officeNumber() {return this._telephoneNumber.number;}
}
class TelephoneNumber {
get areaCode() {return this._areacode;}
get number() {return this._number;}
}
// before
class Person {
constructor() {
this._telephonNumber = new TelephoneNumber()
}
get officeAreaCode() {return this._telephonNumber.areaCode;}
get officeNumber() {return this._telephoneNumber.number;}
}
class TelephoneNumber {
get areaCode() {return this._areacode;}
get number() {return this._number;}
}
// after
class Person {
get officeAreaCode() {return this._officeAreaCode;}
get officeNumber() {return this._officeNumber;}
}
// before
manager = aPerson.department.manager;
// after
manager = aPerson.manager;
class Person {
get manager() {return this.department.manager;} // 중개자 getter 생성
}
// before
manager = aPerson.manager;
class Person {
get manager() {return this.department.manager;} // 중개자 getter 생성
}
// after
manager = aPerson.department.manager;
// before
function foundPerson(people) {
for(let i = 0; i < people.length; i++) {
if (people[i] == "Don") {
return "Don";
}
if (people[i] == "John") {
return "John";
}
if (people[i] == "Kay") {
return "Kay";
}
return "";
// after
function foundPerson(people) {
const candidates = ["Don", "John", "Kay"]
return people.find(p => candidates.includes(p)) || '' ;