본문 바로가기

General

[오브젝트] 10장 상속과 코드 재사용

 

 

전통적인 프로그래밍에서는 코드를 재사용하기 위해 하나는 원래 있던 코드를 스-윽 복사해서 붙여넣었다.

프로그래머는 중복코드를 만나면 혼란을 느낀다. '두 코드가 사실은 같은걸까?', '한 군데만 수정해도 문제가 없을까?', '동료가 실수로 놓친 것일까?' 만약 두 군데 모두 변경해야 하는데 한 군데만 변경한다면 버그로 이어질 것이다. 신뢰할 수 있고, 수정하기 쉬운 코드를 작성하려면 중복을 제거하는 것이 좋다.

단, 모양이 비슷하다고 해서 모두가 코드 중복인 것은 아니다. 코드가 중복되는가를 판단하려면, 요구사항이 변경되는 상황을 가정해보자. 요구사항이 변경되었을 때, 두 군데 모두 변경해야 한다면 코드 중복이 맞다.

 

객체지향 프로그래밍에서는 코드 재사용을 위해 상속 또는 합성이라는 방법을 떠올릴 수 있다. 10장에서는 상속, 11장에서는 합성에 대해 알아본다. 먼저 상속에 대해 알아보자.

 

상속

기존 코드와 다른 부분만 '추가'해서 기능을 확장하는 방법을 차이에 의한 프로그래밍(programming by difference) 이라고 부른다. 

상속은 이렇게 중복 코드를 제거하고 코드를 재사용하는 가장 대표적인 방법이라고 할 수 있다. 상속은 이미 존재하는 클래스의 코드를 기반을 활용해 다른 부분을 쉽고 빠르게 구현할 수 있도록 해준다. 이미 이해하고 있는 익숙한 개념을 활용해 새로운 개념을 만들어내는 방식이기 때문에 더욱 강력하다.

상속은 여러 클래스에 공통적으로 포함된 중복 코드를 하나의 클래스로 모으고, 원래 클래스에서 중복 코드를 제거한 후 옮겨진 클래스를 상속관계로 연결하면 완성된다.

코드 중복을 시작으로 상속이라는 개념을 소개했지만, 상속은 타입 계층을 구조화하기 위한 목적으로만 사용해야 한다. 단순히 코드 재사용이라면 상속을 사용하면 안된다. 이어서 상속의 문제점에 대해 알아보자.

 

"취약한 기반클래스 문제"

주니어 개발자들의 흔히 하는 실수 중에 하나가 상속의 매력에 흠뻑 취해 모든 설계에 상속을 적용하려고 하는 것이다. 그러나 상속의 남용은 위험하다.

상속을 하면 자손클래스가 부모클래스의 구현 세부사항에 의존하도록 만든다. 따라서 상속을 사용한다면 취약한 기반클래스 문제(Fragile/Brittle Base Class Problem)를 피해갈 수 없다. 취약한 기반클래스 문제란, 부모 클래스가 변경되었을 때 자식 클래스가 영향을 받는 현상 말한다. 자식클래스와 부모클래스의 결합도를 높아져, 캡슐화의 장점이 희석되어 버린다.

상속 관계를 추가하면 추가할 수록, 전체 시스템의 결합도는 높아진다. 부모클래스의 구현을 변경하는 작은 변경에도, 상속 계층에 속한 모든 자손클래스들이 영향을 받기 쉬워진다. 극단적인 경우, 부모클래스의 일부를 수정하고 싶은데 모든 자식클래스를 수정해야하는 상황이 되어버릴 수 있다.

다음은 취약한 기반클래스 문제의 대표적인 예시들이다.

  • 불필요한 인터페이스 상속 문제
    • 자식 클래스에게 적합하지 않은 부모 클래스의 오퍼레이션이 상속되어 자식 클래스의 상태가 불안정해진다.
    • 예) JDK의 java.util.Properties와 java.util.Stack 
  • 메서드 오버라이딩 오작용 문제
    • 자식 클래스가 부모 클래스의 메서드를 오버라이딩 해서 사용하고 있는데 부모 클래스의 메서드 호출 방법에 영향을 받는다.
    • 예) java.util.HashSet을 상속받은 InstrumentedHashSet
  • 부모클래스와 자식클래스 동시 수정 문제
    • 자식 클래스와 부모 클래스가 개념적으로 결합해서 부모 클래스에서 변경사항이 발생했는데 자식 클래스도 함께 변경해주어야 한다.
    • 예) Playlist를 상속받은 PersonalPlaylist

 

상속을 위한 경고 ⚠️

  • 자식 클래스의 메서드 안에서 super 참조를 이용해 부모 클래스의 메서드를 직접 호출할 경우 두 클래스는 강하게 결합된다. super 호출을 제거할 수 있는 방법을 찾아 결합도를 제거하라. 
  • 상속 받은 부모 클래스의 메서드가 자식 클래스의 내부 구조에 대한 규칙을 깨뜨릴 수 있다.
  • 자식 클래스가 부모 클래스의 메서드를 오버라이딩할 경우 부모 클래스가 자신의 메서드를 사용하는 방법에 자식 클래스가 결합될 수 있다.
  • 클래스를 상속하면 결합도로 인해 자식 클래스와 부모 클래스의 구현을 영원히 변경하지 않거나, 자식 클래스와 부모 클래스를 동시에 변경하거나 둘 중 하나를 선택할 수 밖에 없다.

 

다음 장에서는 상속보다 더 우아하게 코드를 재사용하면서 상속의 단점을 피할 수 있는 합성에 대해 알아본다.

 

출처: 오브젝트(코드로 이해하는 객체지향 설계) - 조영호 님