본문 바로가기
개인 공부/Java (이펙티브 자바)

[이펙티브 자바] 아이템 18 : 상속보다 컴포지션을 사용하라

by 희조당 2023. 2. 14.
728x90

🎯 학습 목표

  • 상속과 캡슐화
  • 컴포지션이란? (feat. DI)

📌 상속보단 컴포지션

이번 아이템에서 상속의 문제점과 왜 컴포지션을 사용해야 하는지 이야기하고 있다.

우선 상속을 지양해야하는 이유를 알아보자.

🧐 상속과 캡슐화

책에서는 상속이 캡슐화를 깨뜨린다고 말한다. 하지만 나는 '상속이 캡슐화를 깰 수도 있다'라는 말이 맞다고 생각한다.

상속의 문제점은 다음과 같다.

  • 상속은 결합도를 크게 높여 유연성을 떨어트린다.
  • Java에서는 모호성 때문에 다중상속을 지원하지 않는다. (다이아몬드 문제)

이런 문제들이 존재함에도 코드의 중복을 줄이는 강력한 수단임은 틀림없다.

따라서, 정말로 'is - a" 관계일 때만 상속을 사용해야 한다.


👀 컴포지션이란? (feat. DI)

한 객체에서 다른 객체를 포함하는 새로운 객체를 만드는 것을 말한다. 인스턴스 변수로 객체의 참조를 가지는 것이다.

언어적으로 이해하면 Com·position에서 Com이 '같이'라는 뜻을 가지므로 '같이 위치한다'라는 뜻도 가진다.

 

책에서 제시된 예제의 문제점과 해결방법은 다음과 같다.

  • addAll 메서드를 재정의하지 않음으로 해결할 수 있다. 상위 클래스의 로직이 변경된다면 동작을 보장할 순 없다.
  • addAll 메서드를 아예 다르게 재정의해서 해결할 수 있다. 하지만 성능을 보장할 수 없고, 오류가 발생할 수도 있다.
  • 추가적인 메서드와 필드에 대해서 하위 클래스에서 구현해주지 못하면 보안상의 구멍이 발생할 수 있다.
  • 재정의를 하지 않고 하위 클래스에서 새롭게 구현한 메서드와 같은 시그니처를 가진 메서드가 상위 클래스에서 생길 수도 있다.

😎 왜 컴포지션?

컴포지션을 사용하면 기존 클래스의 영향을 벗어날 수 있다.

따라서, 어떤 새로운 메서드를 추가해도 영향을 받지 않고 상속과 유사하게 사용할 수 있다.

🤔 DI랑 비슷한데..?

Composition을 구현할 때 인스턴스 변수에 해당 객체의 참조를 넣어준다. 

언뜻 보니 CompositionDependency Injection이 매우 비슷해 보인다. 하지만 전혀 다른 형태의 개념이다.

객체 합성(Composition)은 객체의 구성 방식에 대한 개념이고, 의존성 주입(DI)은 객체의 관계에 대한 개념이다.

토비님의 답변

컴포지션은 높은 결합도를 가질 수밖에 없다. 하지만 의존성 주입이라는 패턴을 통해서 동적으로 의존관계를 만들어준다면 높은 결합도를 해결할 수 있다.

둘은 다른 형태의 개념이기 때문에 같이 사용될 수 있던 것이다. 스프링에서 우리가 흔히 사용하는 형태가 이 두 개념의 결합이라는 것을 알 수가 있다.

따라서, 서로 밀접한 관계가 있어서 혼동할 수 밖에 없었고, 다이어그램으로 봤을 때 비슷하게 보일 수밖에 없던 것이다.

 

✍️ Bonus!!

다른 인스턴스를 감싸는 클래스를 Wrapper Class라고 한다.

또 다른 말로, 다른 인스턴스의 기능을 덧씌우는 패턴이라고해서 데코레이터 패턴이라고도 한다.


😋 정리

상속은 재사용성을 높여주는 좋은 수단임이 분명하지만 좋은 것, 나쁜 것 안 가리고 승계한다.

따라서 상속을 고민했다면, 옳은 설계인지 고민하고 분명한 'is-a' 관계인지 확인하자.

 


😋 지극히 개인적인 블로그지만 훈수와 조언은 제 성장에 도움이 됩니다 😋

 

 

댓글