개발 공부 기록하기/01. JAVA & Kotlin

짧은 코멘트와 함께하는 이펙티브 자바) #20 추상 클래스보다는 인터페이스를 우선하라

lannstark 2020. 11. 10. 21:56

짧은코멘트

  1. 요약을 잘해서 생략. 추상 클래스보다는 인터페이스를 왜 우선해야 하는지 어떤 경우에는 추상 클래스가 효과적일 수 있는지 잘 제시되어 있다.

추상 클래스보다는 인터페이스를 우선하라

자바가 제공하는 다중 구현 메커니즘은 인터페이스와 추상 클래스 두 가지이다. 둘의 가장 큰 차이는 추상 클래스가 정의한 타입을 구현하는 클래스는 반드시 추상 클래스의 하위 클래스가 되어야 한다는 점이다. 자바는 단일 상속만 지원하니, 추상 클래스 방식은 새로운 타입을 정의하는 데 제약을 안게 되는 셈이다.

인터페이스를 사용하면 장점이 몇 가지 있다.

  • 기존 클래스에도 손쉽게 새로운 인터페이스를 구현해 넣을 수 있다.
  • 인터페이스는 믹스인 정의에 안성맞춤이다.
  • 인터페이스로는 계층구조가 없는 타입 프레임워크를 만들 수 있다.
  • 만약 추상 클래스와 상속을 이용해 같은 구조를 만들려면 조합 폭발(combinatorial explosion)이 일어나게 된다.
  • 래퍼 클래스와 함께 사용하면 인터페이스는 기능을 향상시키는 안전하고 강력한 수단이 된다.

디폴트 메소드

  • 인터페이스의 메소드 중 구현 방법이 명백한 것이 있다면, 그 구현을 디폴트 메소드로 제공해 프로그래머들의 일감을 덜어줄 수 있다.
  • 디폴트 메소드를 제공할 때는 상속하려는 사람을 위한 설명을 @implSpec 태그를 붙여 문서화해야 한다.
  • 디폴트 메소드에 equals와 hashCode와 같은 메소드를 정의해서는 안된다.

추상 골격 구현 클래스

인터페이스와 추상 골격 구현 클래스를 함께 제공하는 식으로 인터페이스와 추상 클래스의 장점을 모두 취하는 방법도 있다. 인터페이스로는 타입을 정의하고, 필요하면 디폴트 메소드 몇 개도 제공한다. 골격 구현 클래스는 나머지 메소들까지 구현한다. (템플릿 메소드 패턴)

골격 구현 클래스를 바로 상속받아 이용하는 방법 외에도, 우회적으로 이용할 수 있다. 인터페이스를 구현한 클래스에서 해당 골격 구현을 확장한 private 내부 클래스를 정의하고, 각 메소드 호출을 내부 클래스의 인스턴스에 전달하는 것이다.

래퍼 클래스와 비슷한 이 방식을 시뮬레이트한 다중 상속(simulated multiple inheritance)이라 하며, 다중 상속의 많은 장점을 제공하는 동시에 단점은 피하게 해준다.

골격 구현은 기본적으로 상속해서 사용하는 걸 가정하므로, 위에서 언급한 상속을 고려한 설계와 문서화의 지침이 모두 적용된다.