이전에 공부한 자바스크립트에서 프로토타입 기반의 상속 개념을 경험했다.
하지만, 객체의 특성을 다른 객체로 상속하는 것을 가능하게 하는 메커니즘인 자바스크립트의 프로토타입 체계는 엄밀히 말해서 상속이라기 보단 체이닝을 통해 접근 권한을 위임하는 것에 가까운 개념이었다.
반면, 클래스로 상속화를 구축한 자바는 '상속'이라는 워딩에 보다 적합한 체계를 갖는다.

상속의 정의

기존 클래스를 활용해 새로운 클래스를 생성시킨다.

child class (sub class, derived class) extends parent class(super class, base class)

기존 클래스를 재사용성하기 때문에 생산성과 유지보수성에 기여하고, 상속 후 코드의 추가 및 변경이 용이해 코드 중복을 최소화할 수 있고 확산성에 용이하다.

자식 클래스가 인스턴스를 생성하면, 해당 인스턴스는 부모 클래스와 자식 클래스의 모든 멤버 변수 및 메소드를 갖게 된다. 자손 클래스에선 부모 클래스 보다 더욱 구체적인 표현이 가능하다.

상속으로 생성된 모든 자식 클래스는, 다른 자식 클래스와 어떠한 관계도 갖지 않으며 오직 부모 클래스와의 상하 관계만 존재한다.

이를 A is a B 관계라고 하는데, A 클래스는 B이다. 즉,A는 B에 상속된다고 표현할 수 있기 때문이다.

ES6 이후의 자바스크립트도 객체의 상태와 기능을 정의한 틀인 클래스 개념이 존재하지만, 자바스크립트의 클래스를 통해 생성된 객체는 함수의 프로토타입 객체에 연결되며 생성자 함수 패턴을 좀 더 클래스답게 보이게 하도록 하는 일종의 모방에 가깝다. 또한 객체는 클래스를 거치지 않아도 되고, 심지어 다른 객체를 통해 정의되는 차등 상속 개념을 따른다.

반면, 클래스 기반 언어인 자바에서는 모든 상속이 클래스를 통해서만 이뤄지며 클래스의 인스턴스인 객체는 오직 클래스를 통해서 정의돼야 한다. 다만 클래스에서 정의된 모든 멤버에 대한 복사본이기 때문에, 사실상 클래스와 인스턴스는 서로 개별적이다.

single inheritance

또 다른 객체 지향 언어인 C++은 다중 상속이 가능한 언어이지만, 자바의 클래스는 오직 하나의 클래스만 상속 받을 수 있다.

왜냐하면, 클래스 간 관계가 매우 복잡해지고 상속 받은 멤버 간 이름을 구별하기 어렵기 때문이다.

만약 두 클래스에서 상속받았다고 가정했을 때, 동명의 메소드나 매개변수를 사용하려면 매우 복잡한 상황이 야기되기 때문에 자바는 다중 상속 개념을 포기하고 단일 상속만 허용한다.

Object class

자바스크립트와 비슷하게, 자바의 모든 상속 계층 최상위에 위치한 건 Object이다. 그래서 Object 클래스가 가진 멤버변수나 메소드 등은 모든 클래스에서 사용할 수 있다.

다음은 Object 클래스가 가진 멤버들이다. 멤버변수는 없고 오직 11개의 메소드만 존재한다.

namedescription
protected Object clone()객체 자신의 복사본을 반환
protected void finalize()객체가 소멸될 때 가비지 컬렉터에 의해 자동 호출, 이때 수행될 코드가 있다면 오버라이딩
boolean equals(Object obj)객체 자신과 객체 obj가 같은 객체인지 알려준다.
Class getClass()객체 자신의 클래스 정보를 담는 Class 인스턴스를 반환
int hashCode()객체 자신의 해시 코드 반환
String toString()객체 자신의 정보를 문자열로 반환
void notify()객체 자신을 사용하려고 기다리는 스레드를 하나만 깨운다.
void notifyAll()객체 자신을 사용하려고 기다리는 모든 스레드를 깨운다.
void wait()다른 스레드가 위 두 메소드 호출 전까지 현재 스레드를 지정된 시간동안 기다리게 한다.

이는 추후 java.lang 패키지를 공부할 때 좀 더 자세히 다루도록 하자.

상속의 단점

상속화를 잘못 사용다면 몇 가지 문제가 생긴다.

캡슐화 위반

우선, 캡슐화를 위반할 수 있다.

상속을 하게 되면 부모 클래스의 메소드나 멤버 변수들을 자식 클래스에서 접근할 수 있기 때문에 캡슐화와 은닉화를 위반할 수 있다.

바로 자식 클래스가 부모 클래스의 멤버 변수를 그대로 사용하거나, 메소드를 재정의해 사용(오버라이딩)하고, 인과관계를 해치는 경우에 캡슐화에 손상을 줄 수 있는 것이다.

클래스 결합 문제

만약 자식 클래스의 응집도 cohesion가 높지 않은, 즉 자신의 고유한 역할에 집중하지 못한채 부모로부터 독립하게 된다면 부모 클래스에 지나친 의존성 coupling을 띄게 된다.

그러나 이러한 방식으로 클래스를 설계한 뒤 부모 클래스가 변경된다면 자식 클래스의 캡슐화가 깨지거나 많은 부분을 수정하는 번거로움이 생길 수 있다.

궁극적으로, 에러의 구렁텅이에 빠질 수 있다....

상속을 보완할 수 있는 개념

Composition

클래스의 상속을 지양하고 새로운 클래스를 생성하여 private 필드로 인스턴스 변수를 생성해 기존 클래스의 인스턴스를 참조하도록 설계하는 방법이다.

하나의 거대한 클래스를 만드는 것보다 단위 별로 응집도 cohesion가 높은 여러 자식 클래스를 만들고 상황에 따라 포함 관계 Composition를 활용하면, 보다 간결하고 재사용성을 극대화할 수 있다. 그렇게 생성된 클래스는 기존 클래스의 구현 방식을 벗어나고, 기존 클래스에 새로운 메소드가 추가되더라도 전혀 영향을 받지 않는다.

이를 A has a B 관계라고 하는데, A는 B를 가지고 있다고 표현한다.

컴포지션은 그저 메서드를 호출하는 방식으로 동작하기 때문에 캡슐화를 깨뜨리지 않는다.

이외에도 abstract 클래스를 활용해 부모 클래스의 미완성 메소드를 자식 클래스에서 재정의하여 완성하는, 정제 refine할 때만 상속을 사용하거나 인터페이스 implement 방식으로 다중 상속을 하는 등으로 상속으로 발생될 문제를 보완할 수 있겠다. 해당 내용들은 추후 자세히 공부한 후 다루도록 하자.


본 후기는 유데미-웅진씽크빅 취업 부트캠프 3기 백엔드 과정 학습 일지 리뷰로 작성되었습니다.

유데미 바로가기 / STARTERS 취업 부트캠프 공식 블로그 보러가기


🧷 참고 교재

profile
개발이란?

0개의 댓글