상속과 코드 재사용에 대한 내용이다
자세한 내용이 궁금하면 오브젝트를 펼쳐보는 걸 추천드립니다.📖
상속과 중복 코드
중복 코드는 모두를 의심하게 만든다. 이것만으로 제거하기 충분한 이유지만 결정적이 이유는 따로 있다.
DRY 원칙
중복 코드는 변경을 방해한다. 이게 중복 코드를 제거해야 하는 가장 큰 이유다. 중복 코드는 수정과 테스트에 드는 비용을 증가시키고 공황상태로 몰아넣을 수 있다.
중복 여부의 판단 기준은 변경이다. 변경이 생겼을 때 두 코드를 수정해야 한다면 중복이다. 함께 수정이 안되면 중복이 아니다.
수정하기 쉬운 소프트웨어를 만드는 방법 중 하나는 중복을 제거하는 것이다. 반복하지 마라(Don't Repeat Yourself)의 의미로 쓰이는 원칙이 DRY 원칙이다.
모든 지식은 시스템 내에서 단일하고, 애매하지 않고, 정말로 믿을 만한 표현 양식을 가져야 한다.
상속을 이용해서 중복 코드 제거하기
이미 존재하는 클래스와 유사한 클래스가 필요하다면 코드를 복사하는게 아닌, 상속을 이용해서 재사용하는 게 상속의 기본 아이디어다.
하지만 재사용 목적으로 사용되는 상속에는 여러 문제가 있다.
취약한 기반 클래스 문제 (Fragile Base Class Problem, Brittle Base Class Problem)
상속은 자식 클래스와 부모 클래스의 결합도를 높인다. 부모가 바뀌면 자식도 영향을 받게 되는 현상을 취약한 기반 클래스 문제라고 부른다. 이건 상속이 피할 수 없는 객체지향 프로그래밍의 근본적인 취약성이다.
취약한 기반 클래스는 캡슐화를 약화시키고 결합도를 높인다. 상속은 자식 클래스가 부모 클래스의 세부사항을 알게 강요한다. 이런 이유로 상속이 위험하고 피해야 할 이유가 된다.
불필요한 인터페이스 상속 문제
class Stack<E> extends Vector {
...
}
대표적인 잘못된 상속으로 java.util.Stack이 있다. Stack은 나중에 추가된 요소가 가장 먼저 추출되는(LIFO) 자료구조다.
자바의 초기에 개발자들은 Stack을 구현하기 위해 Vector를 상속받아 구현했다.
Vector는 임의의 위치에서 요소를 추출하고 삽입하는 리스트 형태의 자료 구조다.
무슨 문제가 생길지 예상이 가는가? 자료구조 형태가 전혀 다른데 상속받아 구현했다.
Stack<String> stack = new Stack<>;
stack.push("1st");
stack.push("2nd");
stack.push("3nd");
stack.add(0, "4th");
assertEquals("4th", stack.pop()); // 에러 발생
상속 주의 사항
- 자식 클래스의 메서드 안에서 super 참조를 이용해 부모 클래스의 메서드를 직접 호출할 경우 자식과 부모는 강하게 결합된다. super 호출을 최대한 제거하여 결합도를 제거하라
- 부모 클래스의 메서드가 자식 클래스의 내부 구조에 대한 규칙을 깨트릴 수 있다
- 자식이 부모의 메서드를 오버라이딩할 경우 부모가 자신의 메서드를 사용하는 방법에 자식이 결합될 수 있다.
- 결합도로 인해 부모와 자식은 영원히 변경하지 않거나, 동시에 변경하거나 둘 중 하나를 선택해야 한다.
추상화에 의존하자
상속으로 생긴 결합도를 벗어나려면 부모와 자식 모두 추상화에 의존하도록 수정해야 한다.
- 두 메서드가 유사하게 보인다면 차이점을 메서드로 추출하라.
- 부모 클래스의 코드를 하위로 내리지 말고 자식 클래스의 코드를 상위로 올려라. 자식 클래스에서 구현해야 할 메서드를 부모에서 추상 메서드로 제공하라.
추상화가 핵심
상속 계층이 코드를 진화시키는 데 걸림돌이 된다면 추상화를 찾아내고 상속 계층 안의 클래스들이 그 추상화에 의존하도록 리팩터링 하고 차이점을 메서드로 추출하고 공통적인 부분은 부모 클래스로 이동하라.
피할 수 없는 문제
상속은 부모의 메서드뿐만 아니라 인스턴스 변수도 결합하게 만든다. 인스턴스의 변수가 변하지 않는다면 행동을 추상화하는 것으로 독립적으로 진화할 수 있다. 하지만 책임을 잘 분리해도 인스턴스 변수가 변하면 상속 계층 전반에 변경을 유발한다.
즉, 상속은 행동을 추상화하여 어느 정도 안정시키겠지만 인스턴스 변수에 변화에 대한 불안감은 갖고 가야 한다.
차이에 의한 프로그래밍(Programming by difference)
상속같이 기존 코드와 다른 부분만을 추가함으로써 애플리케이션의 기능을 확장하는 방법을 차이에 의한 프로그래밍이라고 부른다.
차이에 의한 프로그래밍 목표는 중복 코드를 제거하고 코드를 재사용하는 것이다. 여기서 재사용 가능한 코드란 심각한 버그가 없는 코드다.
'서적 > 오브젝트: 코드로 이해하는 객체지향 설계' 카테고리의 다른 글
오브젝트 12_ 다형성 (0) | 2021.06.10 |
---|---|
오브젝트 11_ 합성과 유연한 설계 (0) | 2021.06.10 |
오브젝트 09_ 유연한 설계 (0) | 2021.06.09 |
오브젝트 08_ 의존성 관리하기 (0) | 2021.06.09 |
오브젝트 07_ 객체 분해 (0) | 2021.06.09 |