[리팩터링 2판] 12. 상속 다루기

Ash·2021년 12월 26일
0

12.1 메서드 올리기

  • 가장 쉬운 경우: 본문 코드가 동일한 경우 -> 복사+붙여넣기
  • 어려운 경우: 본문에서 참조하는 필드들이 서브클래스에만 있는 경우 -> 필드를 먼저 슈퍼클래스로 올린 후 메서드를 올려야함

12.2 필드 올리기

하위 클래스에 있는 필드들 중 비슷하게 쓰이는 필드가 있다고 판단되면 (필드명이 다르더라도 기능을 보아야함.) 슈퍼 클래스로 올린다.
필드를 옮기면 해당 필드를 사용하는 동작을 서브 클래스에서 슈퍼클래스로 올릴 수도 있다.

12.3 생성자 본문 올리기

12.1, 12.2는 간단하게 진행이 가능하지만 생성자의 경우 고려해야할 점이 많다.
1. 슈퍼클래스에 생성자가 없다면 정의하고 서브클래스의 생성자들에서 슈퍼클래스의 생성자가 호출되는지 확인한다.
2. 공통 문장을 모두 super() 호출 직후로 변경한다. (문장 슬라이스)
3. 공통 코드를 슈퍼클래스에 추가하고 서브 클래스에서는 제거한다.
생성자 매개변수 중 공통 코드에서 참조하는 값은 모두 super()로 건넨다.
4. 테스트
5. 생성자 시작 부분으로 옮길 수 없는 공통 코드에는 함수 추출하기 + 메서드 올리기를 차례로 적용한다.

12.4 메서드 내리기

하나 또는 소수의 서브 클래스에서 사용되는 메서드의 경우 슈퍼클래스 -> 서브클래스로 이동

12.5 필드 내리기

하나 또는 소수의 서브 클래스에서 사용되는 필드의 경우 슈퍼클래스 -> 서브클래스로 이동

12.6 타입 코드를 서브클래스로 바꾸기

// bad case
function createEmployee(name, type) {
	return new Employee(name, type);
}

// good case
function createEmployee(name, type) {
	switch(type) {
    	case "engineer": return new Engineer(name);
        case "salesperson": return new Salesperson(name);
        case "manager": return new Manager(name);
    }
}

비슷한 대상을 특정 특성에 따라 구분하는 경우 타입 코드를 사용하여 분리하게 되는데 이 때 서브클래스를 사용하여 리팩토링 하자.

12.7 서브클래스 제거하기

// bad case
class Person {
	get genderCode() { return "X";}
}

class Male extends Person {
	get genderCode() { return "M";}
}

class FeMale extends Person {
	get genderCode() { return "F";}
}

// good case
class Person {
	get genderCode() { return this._genderCode;}
}

서브클래스가 활용되지 않거나 필요하지 않은 방식으로 만들어지는 경우 제거하고 슈퍼클래스의 필드로 대체하자.

12.8 슈퍼클래스 추출하기

비슷한 일을 수행하는 두 클래스가 보이면 상속 메커니즘을 이용해 비슷한 부분을 공통의 슈퍼클래스로 옮겨 담을 수 있다.
공통된 부분
데이터: 필드 올리기
동작: 메서드 올리기

// bad case
class Department {
	get totalAnnualCost() {}
    get name() {}
    get headCount() {}
}
class Employee {
	get annualCost() {}
    get name() {}
    get id() {}
}
// good case
class Party {
	get name() {}
    get annualCost() {}
}
class Department extends Party {
	get annualCost() {}
    get headCount() {}
}
class Employee extends Party {
	get annualCost() {}
    get id() {}
}

12.9 계층 합치기

어떤 클래스와 부모가 너무 비슷해져서 독립적으로 존재해야 할 이유가 사라질 때 하나로 합쳐야한다.

// bad case
class Employee {}
class Salesperson extends Employee {}

// good case
class Employee {}

12.10 서브클래스를 위임으로 바꾸기

상속의 단점
1. 한 번만 사용할 수 있다.
무언가가 달라져야 하는 이유가 여러 개여도 상속에서는 그중 단 하나의 이유만 선택해 기준으로 삼아야한다.
2. 상속은 클래스들의 관게를 아주 긴밀하게 결합한다.

이 문제를 위임으로 해결할 수 있다.

예시코드 참조

  • 서브 클래스 1개
  • 서브 클래스 여러 개

12.11 슈퍼클래스를 위임으로 바꾸기

상속이 혼란과 복잡도를 키우는 방식으로 이뤄지기도 한다. (이런 경우 위임이 필요함.) 슈퍼클래스의 기능들이 서브클래스에는 어울리지 않는다면 그 기능들을 상속을 통해 이용하면 안된다.
ex) 자바의 스택 클래스

  • 자바의 스택은 리스트를 상속하고 있는데, 의도는 좋으나 리스트의 연산 중 스택에는 적용되지 않는 것들이 많음에도 불구하고 모든 연산이 스택 인터페이스에 전부 노출된다. (리팩토링이 필요한 예제)

상속을 먼저 적용하고 나중에 문제가 생기면 슈퍼클래스를 위임으로 바꾸자.

profile
기록남기기👩‍💻

0개의 댓글