10. 상속과 코드 재사용
태그
비어 있음
날짜
2024년 5월 5일
🏁 상속과 중복 코드
DRY 원칙
중복 코드는 수정과 테스트에 드는 비용을 증가시킨다.
중복 여부를 판단하는 기준은 변경이다. 요구사항이 변경됐을 때 두 코드를 함께 수정해야 한다면 이 코드는 중복이다. 중복 코드를 결정하는 기준은 코드의 모양이 아니다. 모양이 유사하다는 것은 단지 중복의 징후일 뿐이다.
DRY 원칙 모든 지식은 시스템 내에서 단일하고, 애매하지 않고, 정말로 믿을 만한 표현 양식을 가져야 한다.
타입코드 사용하기
요금제를 구분하는 타입코드를 추가하고 타입에 따라 로직을 분기시킬 수 있다. 하지만 타입 코드를 사용하는 클래스는 낮은 응집도와 높은 결합도라는 문제에 시달리게 된다.
상속을 이용해서 중복 코드 제거하기
상속을 염두에 두고 설계되지 않은 클래스를 상속을 이용해 재사용하는 것은 생각처럼 쉽지 않다.
요구사항과 구현 사이의 차이가 크면 클수록 코드를 이해하기 어려워진다.
4장 - 결합도 : 하나의 모듈이 다른 모듈에 대해 얼마나 많은 지식을 갖고 있는 지를 나타내는 정도로 정의
상속을 이용해 코드를 재사용하기 위해서는 부모 클래스의 개발자가 세웠던 가정이나 추론 과정을 정확하게 이해해야 한다.
그렇지 않은 경우 예제 : 코드 중복을 제거하기 위해 상속을 사용했음에도 세금을 계산하는 로직을 추가하기 위해 새로운 중복 코드를 만들어야 한다. 구현이 너무 강하게 결합돼 있기 때문에 발생하는 문제다.
💡
상속을 위한 경고 1
자식 클래스의 메서드 안에서 super참조를 이용해 부모 클래스의 메서드를 직접 호출할 경우 두 클래스는 강하게 결합된다. super 호출을 제거할 수 있는 방법을 찾아 결합도를 제거하라.
상속 관계로 연결된 자식 클래스가 부모 클래스의 변경에 취약해지는 현상을 가리켜 취약한 기반 클래스 문제라고 부른다.
🏁 취약한 기반 클래스 문제
상속은 자식 클래스를 점진적으로 추가해서 기능을 확장하는 데는 용이하지만 높은 결합도로 인해 부모 클래스를 개선하는 것은 어렵게 만든다.
자식클래스가 부모클래스의 구현을 알아야 하므로 캡슐화를 약화시킨다.
객체지향의 기반은 캡슐화를 통한 변경의 통제다.
1. 불필요한 인터페이스 상속 문제
스택이 벡터를 상속 받을때 stack.add가 가능하다.
인터페이스 설계는 제대로 쓰기엔 쉽게, 엉터리로 쓰기엔 어렵게 만들어야 한다.
퍼블릭 인터페이스에 대한 고려 없이 단순히 코드 재사용을 위해 상속을 이용하는 것이 얼마나 위험한지를 잘 보여준다. 단순히 코드를 재사용하기 위해 불필요한 오퍼레이션이 인터페이스에 스며들도록 방치해서는 안 된다.
💡
상속을 위한 경고 2
상속받은 부모 클래스의 메서드가 자식 클래스의 내부 구조에 대한 규칙을 깨트릴 수 있다.
2. 메서드 오버라이딩의 오작용 문제
Java
복사
public class InstrumentedHashSet<E> extends HashSet<E>{
}
A : InstrumentedHashSet<E>
B : HashSet<E>
라 할때 A가 요소를 추가할 때 총 요소의 길이를 증가 시킨다.
그 때 B의 내부함수를 이용하는데 여기서도 총 요소의 길이를 증가 시킨다.
💡
상속을 위한 경고 3
자식 클래스가 부모 클래스의 메서드를 오버라이딩할 경우 부모 클래스가 자신의 메서드를 사용하는 방법에 자식 클래스가 결합될 수 있다.
메서드 오버라이딩으로 인한 파급 효과를 분명하게 문서화해야 한다.
→ 캡슐화가 객체지향의 핵심인데 내부 구현을 공개하고 문서화를 하는 것이 옳은가?
상속은 캡슐화를 희생한다. 캡슐화를 위해서는 코드 재사용을 포기하거나 상속 이외의 다른 방법을 사용해야 한다.
3. 부모 클래스와 자식 클래스의 동시 수정 문제
부모클래스에서 인스턴스로 A: 노래 리스트를 가지고 있는데 B: {싱어,노래}맵을 추가한다면
자식클래스에서 A의 요소를 삭제할때 B도 삭제해아한다.
→ 부모 클래스를 수정할 때 자식 클래스를 함께 수정해야 할 수 도 있다.
결합도란 달느 대상에 대해 알고 있는 지식의 양이다. 코드 재사용을 위한 상속은 부모와 자식 클래스를 강결합시켜 함께 수정해야 하는 상황이 빈번하다.
💡
상속을 위한 경고4
클래스를 상속하면 결합도로 인해 자식 클래스와 부모 클래스의 구현을 영원히 변경하지 않거나, 자식 클래스와 부모 클래스를 동시에 변경하거나 둘 중 하나를 선택할 수 밖에 없다.
🏁 Phone 다시 살펴보기
상속의 위험을 완화 시키는 방법 → 추상화
차이를 메서드로 추출하라
공통되는 부분을 메서드로 추출하자.
중복 코드를 부모 클래스로 올려라
부모클래스를 추상클래스로 하고 아까 추출한 코드(A)를 여기에 위치시킨다.
필요한 인스턴스도 이동시킨다.
A에서 사용하는 차이나는 부분이 있는 메서드의 시그니처만 추상클래스(B)에 선언한다.
자식클래스에서 B를 오버라이딩한다.
⇒ 추상화에 의존
부모도 자식도 추상화에 의존한다.
DIP도준수한다.
낮은 결합도를 가진다.
여기까지는 객체의 행동의 결합에 대한 방법
⇒ 상속은 자식 클래스가 부모 클래스가구현한 행동 뿐만 아니라 인스턴스 변수에 대해서도 결합되게 만든다.
인스턴스 변수의 추가는 종종 상속 계층 전반에 걸친 변경을 유발한다.
하지만 인스턴스 추기화 로직을 변경하는 것이 두 클래스에 동일한 세금 계산 코드를 중복시키는 것보다는 현명한 선택이다.
메서드 구현에 대한 결합은 추상 메서드를 추가함으로써 어느 정도 완화할 수 있지만 인스턴스 변수에 대한 잠재적인 결합을 제거할 수 있는 방법은 없다.
🏁 차이에 의한 프로그래밍
차이에 의한 프로그래밍의 목표는 중복 코드를 제거하고 코드를 재사용하는 것이다.
상속의 오용과 남용은 애플리케이션을 이해하고 확장하기 어렵게 만든다. 정말로 필요한 경우에만 상속을 사용하라.
표
'책 > 오브젝트' 카테고리의 다른 글
12. 다형성 (0) | 2025.03.17 |
---|---|
11. 합성과 유연한 설계 (0) | 2025.03.17 |
09. 유연한 설계 (0) | 2025.03.17 |
08. 의존성 관리하기 (0) | 2025.03.17 |
07. 객체 분해 (0) | 2025.03.17 |