동일한 일을 하는 메소드를 여러 서브클래스에서 가지고 있다면, 이 메소드를 수퍼클래스로 옮겨라.

동기

  • 중복된 동작을 제거해야 하기 때문입니다. 한쪽은 바꿨는데 다른 쪽은 그대로 라면 수정하기도 번거롭고 나중에 버그가 될 가능성이 높을 것입니다.

Pull Up Method가 필요한 경우는 서브클래스에 있는 메소드가 수퍼클래스에 있는 메소드를 오버라이드하는데 여전히 같은 일을 하는 때입니다.
이 때 성사긴 것은 서브클래스의 메소드에서 수퍼클래스에 없는 메소드나 변수를 참조할 때입니다. 이 때는 메소드도 같이 일반화하거나 수퍼클래스에 추상 메소드를 만들 수 있습니다. (이럴 때 메소드의 시그너쳐를 변경하거나 위임 메소드(?)를 만들어야 할 지도 모른다고 합니다.)
비슷하지만 동일한 메소드가 아닐때는 Form Template Method를 사용할 수 있을지도 모릅니다.

절차

  1. 메소드들을 조사해서 그것이 동일한지 확인한다.
    • 만약 같은 일을 하지만 코드가 다른경우 메소드들 중 하나에 Substitute Algorithm을 사용하여 코드가 동일하게 만들어라.
  2. 메소드가 서로 다른 시그너쳐를 가지고 있다면, 수퍼 클래스에서 사용하고 싶은 시그너처로 바꾼다.
  3. 수퍼클래스에 새로운 메소드를 만들고, 메소드들 중 하나의 몸체를 새로운 메소드에 복사해서 적절히 수정한 후 컴파일한다.
    • 그 메소드가 수퍼클래스에 없는 메소드를 호출한다면, 수퍼클래스에 추상 메소드를 만들어라.
    • 수퍼클래스에 없는 필드를 사용한다면, Pull Up Field 또는 Self Encapsulate Field를 사용하고 추상 get메소드를 선언하여 사용하라.
  4. 서브클래스 중 하나를 골라서 메소드를 삭제한다.
  5. 컴파일, 테스트를 한다.
  6. 수퍼 클래스 메소드만 남을 떄까지 서브클래 메소드를 삭제하고 테스트를 계속한다.
  7. 필요한 타입을 수퍼클래스로 변경할 수 있는지 살펴보기 위해서 이 메소드의 호출부를 살펴본다.

예제

두 개의 서브클래스(RegularCustomer, PreferredCustomer)를 가진 Customer 클래스가 있다. 그리고 두 서브클래스에 있는 createBill 메소드는 둘다 다음과 같은 코드로 동일하다.

void createBill(Date date) {
   double chargeAmount = chatgeFor(lastBillDate, date);
   addBill(date, charge);
}


색칠 된 부분의 코드가 모두 중복되고 있지만 둘 중에 녹색으로 칠해진 chargeFor 메소드는 위로 복사해서 옮길 수가 없습니다. 클래스 몸체가 서브클래스마다 다르기 때문입니다. 이때는 수퍼클래스에 추상 메소드로 선언합니다.


addBill 메소드는 수퍼클래스로 옮겼고 chargeFor 메소드는 수퍼클래스에 추상 메소드로 선언했습니다.(UML 표기상 추상 메소드는 이탤릭체로 표기합니다. 그리고 추상 메소드를 가진 클래스는 추상 클래스가 되기 때문에 클래스 이름도 이탤릭체로 표기했습니다.)