class Department {
get totalAnnualCost() {...}
get name() {...}
get headCount() {...}
}
class Employee {
get annualCost() {...}
get name() {...}
get id() {...}
}
리팩터링 후
class Party {
get name() {...}
get annualCost() {...}
}
class Department extends Party {
get annualCost() {...}
get headCount() {...}
}
class Employee extends Party {
get annualCost() {...}
get id() {...}
}
🧷 배경
비슷한 일을 수행하는 두 클래스가 보이면 상속 메커니즘을 이용해서 비슷한 두 부분을 공통의 슈퍼클래스로 옮겨 닮는다.
🧷 절차
빈 슈퍼클래스를 만든다. 원래의 클래스들이 새 클래스를 상속하도록 한다.
테스트한다.
생성자 본문 올리기, 메서드 올리기, 필드 올리기를 차례로 적용하여 공통 원소를 슈퍼클래스로 옮긴다.
서브클래스에 남은 메서드들을 검토한다. 공통되는 부분이 있다면 함수로 추출한 다음 메서드 올리기를 적용한다.
원래 클래스들을 사용하는 코드를 검토하여 슈퍼클래스의 인터페이스를 사용하게 할지 고민해본다.
🧷 예시
🧷 리팩터링 전
class Employee {
constructor(name, id, monthlyCost) {
this.name = name;
this.id = id;
this.monthlyCost = monthlyCost;
}
get monthlyCost() {
return this._monthlyCost;
}
get name() {
return this._name;
}
get id() {
return this._id;
}
get annualCost() {
return this.monthlyCost * 12;
}
}
class Department {
constructor(name, staff) {
this.name = name;
this.staff = staff;
}
get staff() {
return this._staff.slice();
}
get name() {
return this._name;
}
get totalMonthlyCost() {
return this.staff.map((e) => e.monthlyCost).reduce((sum, cost) => sum + cost);
}
get headCount() {
return this.staff.length;
}
get totalAnnualCost() {
return this.totalMonthlyCost * 12;
}
}
🧷 리팩터링 후
class Party {
constructor(name) {
this._name = name;
}
get name() {
return this._name;
}
get annualCost() {
return this.monthlyCost * 12;
}
}
class Employee extends Party {
constructor(name, id, monthlyCost) {
super(name);
this.name = name;
this.id = id;
this.monthlyCost = monthlyCost;
}
get monthlyCost() {
return this._monthlyCost;
}
get id() {
return this._id;
}
}
class Department extends Party {
constructor(name, staff) {
super(name);
this.name = name;
this.staff = staff;
}
get staff() {
return this._staff.slice();
}
get totalMonthlyCost() {
return this.staff.map((e) => e.monthlyCost).reduce((sum, cost) => sum + cost);
}
get headCount() {
return this.staff.length;
}
}