본문 바로가기

[스터디] OOP - 상속과 코드 재사용

요약

상속을 통해 코드를 재사용하면 부모-자식이 강하게 결합된다.
특히 `super` 참조를 통해 자식에서 부모 클래스의 메소드를 직접 호출하면 두 클래스는 강하게 결합되고,
자식이 부모의 내부 구현을 알아야 하여 캡슐화를 위반한다.
높은 결합도는 변경에 취약한 클래스를 낳는데, 이를 취약한 기반 클래스 문제라고 한다.

취약한 기반 클래스 문제는 다음 세가지 문제를 야기한다.

 

1. 상속받은 부모 클래스의 메소드가 자식 클래스의 내부 구조에 대한 규칙을 깨트릴 수 있다.
2. 자식 클래스가 부모 클래스의 메소드를 오버라이딩하는 경우, 부모 클래스가 자신의 메소드를 사용하는 방법(내부 구현)을 자식이 알아야 한다.
3. 높은 결합도로 인해 자식 클래스와 부모 클래스의 구현을 fix하던가, 아니면 동시에 변경해야 한다.

 

취약한 기반 클래스 문제를 해결하는 방법은 두 클래스간의 차이를 메소드로 추출하여 추상화에 의존하는 것이다.
또한, 부모 클래스를 하위로 내리지 말고(super 참조하지 말고), 자식 클래스의 코드를 상위로 올린다.

이처럼 기존 코드와 다른 부분만을 추가하여 기능을 확장하는 것을 차이에 의한 프로그래밍이라고 한다.

 

실무 예시

약관동의 예제 리팩터링

OOP - 책임 할당하기에서 약관동의 예제를 리팩터링해본다.

 

요구사항 추가

요구사항은 이전과 동일하나, 새로운 유형의 약관항목이 추가되었다.
항목을 동의하자마자 약관상세링크를 새 창으로 띄운다. 또한, 그 항목이 필수항목이라면 약관상세화면을 띄우는 동시에 '동의'로 체크하고, 선택항목이라면 '미동의'상테로 유지한다.
기존 코드에서 위 요구사항을 구현하기 위해 LinkAgreementItem 자식 클래스를 생성하였다.

 

기존 코드

 

리팩터링

AgreementItem 을 상속받은 자식 클래스, CommonAgreementItem , SubAgreementItem , LinkAgreementItemtoggle()clear() 구현체에서 각각 super를 참조하고 있는 것을 볼 수 있다. 이것은 위에서 말한  부모 클래스의 내부 구현을 자식 클래스도 알아야 하므로 결합도를 높이게 된다.

 

따라서 자식 클래스에는 다른 부분만을 남기고, super로 참조한 부모 클래스의 구현을 제거한다. 자식클래스에서 다른 부분은 toggle이 가능한지를 결정해야 하는 로직과, clear 시 초기화해야 할 정보들이다. 따라서 canToggleclearAgreementStatus 를 자식 클래스에 추가한다. 이 때, 차이점은 추상화에 의존하도록 하여 추상 메소드로 정의한다.

 

더보기

추가

LinkAgreementItem 에서 toggle과 동시에 상세링크를 새 창으로 띄우는 기능이 canToggle 에 위치하면 toggle 여부를 관리한다는 하나의 기능 뿐만 아니라 부수적인 기능까지 내포하게 되므로 의도에 맞지 않다.

따라서 해당 구현을 AgreementItem 으로 이동한다.

 

수정한 코드

 

TS 꿀팁

  • export type {Class} 로 상속 불가능한 클래스 생성가능 (Java의 final 같은 키워드)
  • private constructor() 로 new 키워드를 사용을 제한할 수 있음
  • static method는 오로지 원형 클래스의 프로토타입 참조로 사용 가능