Home [Effective Java] Item20. 추상 클래스보다는 인터페이스를 우선하라!
Post
Cancel

[Effective Java] Item20. 추상 클래스보다는 인터페이스를 우선하라!

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

  • 자바가 제공하는 다중 구현 메커니즘 -> 인터페이스, 추상 클래스
    • 자바 8부터 인터페이스도 디폴트 메서드 제공이 가능해져 두 메커니즘 모두 인스턴스 메서드를 구현 형태로 제공 가능
  • 추상 클래스
    • 정의한 타입 구현을 위해 하위 클래스가 필요하다.
    • 자바는 단일 상속만 지원하기에 추상 클래스 방식은 새로운 타입 정의에 제약을 받는다.
  • 인터페이스
    • 선언한 메서드를 모두 정의하고, 일반 규약을 잘 지킨 클래스라면 다른 어떤 클래스를 상속했든 같은 타입으로 취급된다.

인터페이스를 우선해야 하는 이유

1. 기존 클래스에도 손쉽게 새로운 인터페이스를 구현해넣을 수 있다.

  • 인터페이스가 요구하는 메서드를 추가하고, implements 구문만 추가하면 된다.
  • 추상 클래스를 사용한다면, 자바 버전에 따른 추가 기능 구현 시 표준 라이브러리들의 기능을 확장하는 것이 어렵다.

2. 인터페이스는 믹스인(mixin) 정의에 안성맞춤이다.

믹스인 : 클래스가 구현할 수 있는 타입, 믹스인 구현 클래스에 원래의 목적(주된 타입) 외의 선택적 행위를 제공한다고 선언하는 효과를 준다.

  • 대상 타입의 주된 기능에 선택적 기능을 혼합하는 방식이다.
  • 인터페이스는 다중 인터페이스 상속이 가능하기에 선택적 기능의 사용이 가능하다.
  • 마찬가지로 추상 클래스는 기존 클래스에 덧씌울 수 없기 때문에 믹스인 정의에 사용하기 어렵다.

3. 인터페이스로는 계층구조가 없는 타입 프레임워크를 만들 수 있다.

  • 계층적 표현으로 수많은 개념을 구조적으로 잘 표현할 수 있지만, 현실에는 계층 구분이 어려운 개념이 존재한다.
  • 클래스로 이를 표현하려면 가능한 조합 전부를 클래스로 정의한 거대한 계층구조가 만들어질 것이다.
    • 흔히 조합 폭발이라 부르는 현상이다.

4. 래퍼 클래스 관용구와 함께 사용 시, 인터페이스는 기능을 향상시키는 안전하고 강력한 수단이 된다.

  • 타입을 추상 클래스로 정의 시, 기능 추가는 즉 상속을 말한다. 상속 클래스는 래퍼 클래스보다 활용도 떨어지고 깨지기 쉽다.

디폴트 메서드

  • 인터페이스 메서드 중 구현 방법이 명백한 것이 있다면, 그 구현을 디폴트 메서드로 제공해 프로그래머의 일 줄일 수 있다.
  • 디폴트 메서드 제공 시, 상속하려는 사람을 위한 설명을 @implSpec 자바독 태그를 붙여 문서화해야 한다.
  • 제약
    • 인터페이스는 인스턴스 필드를 가질 수 없고, public이 아닌 정적 멤버도 가질 수 없다.
    • 직접 만들지 않은 인터페이스에는 디폴트 메서드를 추가할 수 없다.

인터페이스와 추상 골격 구현 클래스 (템플릿 메서드 패턴)

  • 위 두 가지를 모두 제공함으로써 인터페이스와 추상 클래스의 장점을 모두 취하는 방법도 있다.
    • 인터페이스로 타입 정의, 필요 시 디폴트 메서드 몇개도 함께 제공
    • 골격 구현 클래스는 나머지 메서드 구현
  • 단순히 골격 구현을 확장하는 것만으로 이 인터페이스를 구현하는 데 필요한 일 대부분을 완료함.
  • 네이밍 관례
    • 인터페이스 이름 : Interface
    • 골격 구현 클래스 이름 : AbstractInterface
  • 골격 구현 클래스는 추상 클래스처럼 구현을 도와주는 동시에, 추상 클래스로 타입 정의 시 따라오는 심각한 제약에서는 자유롭다는 이점이 있다.
  • 구조상 골격 구현을 확장하지 못하는 처지라면 인터페이스를 직접 구현한다. 직접 구현하더라도 디폴트 메서드의 이점을 여전히 누릴 수 있다.
  • 골격 구현 클래스를 우회적으로 이용할 수도 있다.
    • 인터페이스를 구현한 클래스에서 해당 골격 구현을 확장하느 private 내부 클래스를 정의
    • 각 메서드 호출을 내부 클래스의 인스턴스에 전달
    • 래퍼 클래스와 비슷한 방식을 시뮬레이트한 다중 상속(simulated multiple inheritance)이라 한다.
    • 즉, 골격 클래스를 private 내부 필드로 두고, 인터페이스 기반 메서드 호출 시 내부 클래스의 메서드가 호출되도록 랩핑하는 것이다.
  • 골격 구현은 기본적으로 상속해서 사용하는 것을 가정하니 아이템 19에서 이야기한 설계 및 문서화 지침을 모두 따라야 한다.

단순 구현

  • 골격 구현의 작은 변종
  • 단순 구현도 골격 구현과 같이 상속을 위해 인터페이스를 구현한 것이지만, 추상 클래스가 아니란 점이 다르다.

핵심 정리

  • 일반적으로 다중 구현용 타입으로는 인터페이스가 가장 적합
  • 복잡한 인터페이스라면 골격 구현을 함께 제공하는 방법을 고려하자
    • 골격 구현은 가능한 한 인터페이스의 디폴트 메서드로 제공한다.
    • 인터페이스에 걸려 있는 구현 상 제약 때문에 골격 구현을 추상 클래스로 제공하기도 한다.(이 경우가 더 흔함)
This post is licensed under younghwani by the author.

[Effective Java] Item19. 상속을 고려해 설계하고 문서화하라. 그러지 않았다면 상속을 금지하라!

[Effective Java] Item21. 인터페이스는 구현하는 쪽을 생각해 설계하라!

Comments powered by Disqus.