리팩터링 2판 12장 정리

Study리팩터링 2판스터디javascript

들어가며

본 게시글은 사내 스터디로 공부한 리팩터링 2판 (마틴 파울러) 12장을 정리 & 요약하는 글입니다.

매 챕터마다 돌아가며 설명을 했기 때문에, 본인이 정리한 일부 주제들만 정리했습니다. (나머지 내용은 추후 업데이트 예정)


Chapter 12. 상속 다루기


12.1 메서드 올리기

Before

class Employee {...}

class Salesman extends Employee {
  get name() {...}
}

class Engineer extends Employee {
  get name() {...}
}

After

class Employee {
  get name() {...}
}

class Salesman extends Employee {...}
class Engineer extends Employee {...}

배경

  • 서브클래스들의 중복 메서드는 슈퍼클래스로 메서드를 올리는 리팩터링

효과

  • 중복 코드를 제거할 수 있음

적용

  • 서브클래스들에 중복된 코드가 존재하는 경우 적용할 수 있음
  • 상황에 따라 함수 매개변수화(11.2)나 필드올리기(12.2) 리팩터링을 먼저 진행해야 함
class Party {
  constructor() {}

  get monthlyCost() {
    return 30
  }
}

class Employee extends Party {
  get annualCost() {
    return this.monthlyCost * 12
  }
}

class Department extends Party {
  get annualCost() {
    return this.monthlyCost * 12
  }
}

const employee = new Employee()
const department = new Department()

적용 절차

예시

// 실내온도 제어 시스템. 사용자는 온도조절기로 온도를 설정할 수 있지만,
// 목표 온도는 난방 계획에서 정한 범위에서만 선택할 수 있음

// HeatingPlan 클래스
class HeatingPlan {
  get targetTemperature(aPlan) {
    if (thermostat.selectedTemperature > this._max) {
      return this._max;
    } else if (thermostat.selectedTemperature < this._min) {
      return this._min;
    } else {
      return thermostat.selectedTemperature;
    }
  }
}

// 호출자
if (thePlan.targetTemperature > thermostat.currentTemperature) { setToHeat();}
else if (thePlan.targetTemperature < thermostat.currentTemperature) { setToCool();}
else { setOff();}

  1. 똑같이 동작하는 메서드인지 면밀히 살펴본다
  • 실질적으로 하는 일은 같지만 코드가 다르다면 본문 코드가 똑같아질 때까지 리팩터링한다.
get annualCost() {
	return this.monthlyCost * 12;
}

  1. 메서드 안에서 호출하는 다른 메서드와 참조하는 필드들을 슈퍼클래스에서 호출하고 참조 할 수 있는지 확인하다
  2. 메서드 시그니처가 다르다면 함수 선언 바꾸기로 슈퍼클래스에서 사용하고 싶은 형태로 통일한다.
  3. 정적 검사를 수행한다.
  4. 서브클래스 중 하나의 메서드를 제거한다.
  5. 테스트한다.
  6. 모든 서브클랫의 메서드가 없어질 때까지 다른 서브클래스의 메서드를 하나씩 제거한다.
class Party {
  constructor() {}

  get monthlyCost() {
    return 30
  }

  get annualCost() {
    return this.monthlyCost * 12
  }
}

class Employee extends Party {}
class Department extends Party {}

const employee = new Employee()
const department = new Department()

12.2 필드 올리기

Before

class Employee {...} // Java

class Salesman extends Employee {
  private String name;
}

class Engineer extends Employee {
  private String name;
}

After

class Employee {
  protected String name;
}

class Salesman extends Employee {...}
class Engineer extends Employee {...}

배경

  • 서브클래스들의 중복 필드를 슈퍼클래스로 올리는 리팩터링
  • 서브클래스들이 독립적으로 개발 되었거나 뒤늦게 하나의 계층구조로 리팩터링된 경우라면 기능이 중복되는 경우가 자주 있음
  • 필드 이름이 같을수도 있지만 다르더라도 비슷하게 사용할 수 있으니 실제 어떻게 사용되는지 분석이 필요함

효과

  • 필드 중복 선언을 제거
  • 해당 필드를 사용하는 동작을 서브 클래스에서 슈퍼 클래스로 옮길 수 있음

적용

  • 완전히 동일하거나 비슷하게 쓰이는 필드들이 서브클래스에 존재하는 경우

  1. 후보 필드들을 사용하는 곳 모두가 그 필드들을 똑같은 방식으로 사용하지 살펴라
  2. 필드들의 이름이 각기 다르다면 똑같은 이름으로 바꾼다(필드 이름 바꾸기)
  3. 슈퍼클래스에 새로운 필드를 생성한다. => 서브클래스에서 이 필드에 접근 할 수 있어야한다. (protected 로 선언하면 된다)
  4. 서브 클래스의 필드들의 제거한다
  5. 테스트한다


참고




Profile picture
@김하연
3년차 프론트엔드 개발자 입니다. 사용자 경험 개선, 코드의 재사용성, 읽기 쉬운 코드에 집중하여 개발합니다.
AboutGithub LinkedinResume
Loading script...