냄새 18. 중재자 Middle Man

  • 캡슐화를 통해 내부의 구체적인 정보를 최대한 감출 수 있다.
  • 그러나, 어떤 클래스의 메소드가 대부분 다른 클래스로 메소드 호출을 위임하고 있다면 중재자를 제 거하고 클라이언트가 해당 클래스를 직접 사용하도록 코드를 개선할 수 있다.
  • 관련 리팩토링
    • "중재자 제거하기 (Remove Middle Man)" 리팩토링을 사용해 클라이언트가 필요한 클래스를 직접 사용하도록 개선할 수 있다.
    • "함수 인라인 (Inlince Function)"을 사용해서 메소드 호출한 쪽으로 코드를 보내서 중재자를 없 앨 수도 있다.
    • "슈퍼클래스를 위임으로 바꾸기 (Replace Superclass with Delegate)"
    • "서브클래스를 위임으로 바꾸기 (Replace Subclass with Delegate)

계속해서 감싸고 감추다보면 정도를 지나칠 때가 있다. 리팩토링 기술은 항상 두 가지 방향에 대해서 동시에 존재한다. 왜냐하면 그때의 비즈니스나 코드 상태에 따라 자연스러움의 기준이 달라질 수 있기 때문이다.

리팩토링 38. 중재자 제거하기 Remove Middle Man

  • "위임 숨기기"의 반대에 해당하는 리팩토링.
  • 필요한 캡슐화의 정도는 시간에 따라 그리고 상황에 따라 바뀔 수 있다.
  • 캡슐화의 정도를 "중재자 제거하기"와 "위임 숨기기" 리팩토링을 통해 조절할 수 있으 다.
  • 위임하고 있는 객체를 클라이언트가 사용할 수 있도록 getter를 제공하고, 클라이언트 는 메시지 체인을 사용하도록 코드를 고친 뒤에 캡슐화에 사용했던 메소드를 제거한다.
  • Law of Demeter를 지나치게 따르기 보다는 상황에 맞게 활용하도록 하자.
    • 디미터의 법칙, "가장 가까운 객체만 사용한다."

"왜 자꾸 특정 메서드를 통해서 접근해야하지?"와 같은 문제점이 자꾸만 발견된다면 중재자를 제거해볼 수 있다.

리팩토링 39. 슈퍼클래스를 위임으로 바꾸기 Replace Superclass with Delegate

  • 객체지향에서 "상속"은 기존의 기능을 재사용하는 쉬우면서 강력한 방법이지만 때로는 적절하지 않은 경우도 있다.
  • 서브클래스는 슈퍼클래스의 모든 기능을 지원해야 한다.
    • Stack이라는 자료구조를 만들 때 List를 상속 받는것이 좋을까?
  • 서브클래스는 슈퍼클래스 자리를 대체하더라도 잘 동작해야 한다.
    • 리스코프 치환 원칙
  • 서브클래스는 슈퍼클래스의 변경에 취약하다.
  • 그렇다면 상속을 사용하지 않는 것이 좋은가?
    • 상속은 적절한 경우에 사용한다면 매우 쉽고 효율적인 방법이다.
    • 따라서, 우선 상속을 적용한 이후에, 적절치 않다고 판단이 된다면 그때에 이 리팩토링을 적용하자.

소프트웨어에 "항상"이라는 말은 어울리지 않는다. 때에 따라 상속이 유리할수도 있고 위임이 유리할수도 있다.

리팩토링 40. 서브클래스를 위임으로 바꾸기 Replace Subclass with Delegate

  • 어떤 객체의 행동이 카테고리에 따라 바뀐다면, 보통 상속을 사용해서 일반적인 로직은 슈퍼클래스에 두고 특이한 케이 스에 해당하는 로직을 서브클래스를 사용해 표현한다.
  • 하지만, 대부분의 프로그래밍 언어에서 상속은 오직 한번만 사용할 수 있다.
    • 만약에 어떤 객체를 두가지 이상의 카테고리로 구분해야 한다면?
    • 위임을 사용하면 얼마든지 여러가지 이유로 여러 다른 객체로 위임을 할 수 있다.
  • 슈퍼클래스가 바뀌면 모든 서브클래스에 영향을 줄 수 있다. 따라서 슈퍼클래스를 변경할 때 서브클래스까지 신경써야 한다.
    • 만약에 서브클래스가 전혀 다른 모듈에 있다면?
    • 위임을 사용한다면 중간에 인터페이스를 만들어 의존성을 줄일 수 있다.
  • "상속 대신 위임을 선호하라."는 결코 "상속은 나쁘다."라는 말이 아니다.
    • 처음엔 상속을 적용하고 언제든지 이런 리팩토링을 사용해 위임으로 전환할 수 있다.