Java

왜 상속보다는 조합을 사용해야할까?

개발자가 반드시 정복해야 할 객체지향과 디자인 패턴에서 발췌한 글이 포함되어 있습니다. 

 

요즘 우아한 테크코스를 진행하며 가장 자주 듣는 문장 중 하나인 것 같다. 상속보다 조합(Composition)! 

왜 우리는 상속보다 조합을 이용해야할까?

 

상속과 재사용

상속을 사용하면 쉽게 다른 클래스의 기능을 재사용하면서 추가 기능을 확장할 수 있다. 그러므로 기능의 재사용이라는 측면에서 상속은 아주 매력적인 솔루션이다. 하지만 상속은 변경의 유연함이라는 측면에서 단점을 갖는다.

 

상속을 통한 재사용의 단점 - 상위 클래스 변경이 어렵다.

상위 클래스에서 무언가 변경이 발생해야 할 때, 그 전파는 하위 클래스까지 이어지게 된다. 특히 계층도가 커질수록 상위 클래스의 변경이 어려워진다. 상속 계층을 따라 상위 클래스의 변경이 하위 클래스에 영향을 미칠 수 있기 때문이다. 최악의 경우에는 클래스 계층도에 있는 클래스들을 하나의 거대한 단일 구조처럼 만들어버리는 결과를 초래할 수 있다. 

 

상속을 통한 재사용의 단점 - 클래스가 불필요하게 증가한다.

유사한 기능을 확장하게 하는 과정에 있어 클래스의 개수가 불필요하게 증가할 수 있다. 개발자가 반드시 정복해야 할 객체지향과 디자인 패턴에서 발췌한 예시를 들자면, 파일 보관소를 구현한 Storage 클래스가 있다고 할 때, 제품 출시 이후 보관소의 용량을 아낄 수 있는 방법을 제공해달라는 요구가 발생하였다. 이 요구를 수용키위해 압축 기능을 추가한 CompressedStorage 클래스를 만들었다. 또한 보안 요구가 추가되어 EncryptedStorage 클래스를 추가하였다. 그런데, 보안과 압축 기능을 모두 가진 방법을 제공해달라는 추가 요구가 발생하였다. 기존의 CompressedStorage와 EncryptedStorage가 있음에도 불구하고 동시에 해당 기능을 수행하기 위해서는 CompressedEncryptedStorage라는 새로운 클래스를 생성해야한다. 이와 더불어 이러한 요구가 늘어나게 된다면, 클래스는 불필요하게 많이 증가하게 된다.

 

상속을 통한 재사용의 단점 - 상속의 오용

ArrayList를 상속한 어떤 컨테이너 클래스가 있다고 보자. 우리는 컨테이너에 물건을 넣을 때 put(put에는 물건을 추가할 때 또다른 로직을 수행하도록 구현되어있었다.)을 이용하도록 설계하였고, 다른 개발자들에게도 그렇게 안내했지만 ArrayList에서 제공되는 add 메서드가 끌린다. add 라는 메서드 명에서도 물건을 넣는다는 기능을 수행하기에 문제가 없어 보인다. 그렇게 add를 수행하게 된다면, 우리가 별도의 로직과 함께 구현해두었던 put의 내부 로직은 수행되지 못하게 된다. 

따라서 상속은 IS-A 관계가 성립될 때에만 사용해야한다. IS-A 관계라 함은 컨테이너ArrayList이다. 가 만족되는 경우에 상속을 수행해야 한다. 

 

따라서, 상속을 사용했을 때에는 상위 클래스 변경의 어려움, 클래스 개수의 불필요한 증가, 상속의 오용 문제가 발생할 수 있다.

 

 

그렇다면, 우리는 어떨 때 상속을 사용해야할까? 상속을 사용할 때에는 재사용이라는 관점이 아닌 기능의 확장이라는 관점에서 상속을 적용해야한다. 또한 추가로 명확한 IS-A 관계가 성립되어야한다. 대표적인 예시로는 안드로이드의 UI위젯 클래스 계층도가 있다. 명확한 IS-A 관계에서 상위 클래스의 기능을 확장시켜나가야하는 경우 상속을 이용하자!

 

 

이에 더불어, 상속보다는 조합에 대해 잘 정리된 글이 있어 레퍼런스로 남겨둔다.

[javable] 상속보다는 조합(Composition)을 사용하자.