본문 바로가기

Programming/JAVA

[Effective JAVA] item 20 : 추상 클래스 보다는 인터페이스를 우선하라

서론

  • 자바의 다중 구현 메커니즘: 인터페이스, 추상 클래스
    • 둘의 차이
      - 추상 클래스가 정의한 타입을 구현하는 클래스는 반드시 추상 클래스의 하위 클래스가 되어야 함 
      - 자바는 단일 상속만 지원하기 때문

인터페이스

  1. 기존 클래스에 쉽게 새로운 인터페이스 구현 가능
  2. 인터페이스가 요구하는 메서드를 추가하고, 클래스 선언에 implements 구문만 추가하면 됨
  3. 인터페이스는 믹스인(mixin) 정의에 안성맞춤
    1. 믹스인(mixin)
      1. 대상 타입의 주된 기능에 선택적 기능을 혼합(mix in)하는 것 
      2. 클래스가 구현할 수 있는 타입
      3. 원래 주된 타입 외에 특정 선택적 행위를 제공하다고 선언하는 효과를 줌
    2. 추상 클래스는 기존 클래스에 덧씌울 수 없어 믹스인 정의가 불가함
      => 클래스는 두 개의 부모를 가질 수 없고, 클래스 계층 구조에 믹스인 삽입하기에 합리적 위지가 없기 떄문
  4. 인터페이스로 계층구조가 없는 프레임워크를 만들 수 있음
    1. 타입을 계층적으로 정의하면 수많은 개념의 구조적 표현이 가능하나 현실에서 계층 구조를 엄격히 구분하기 어려운 개념이 존재
    2. 내가 이해하기에..
      1. 인터페이스는 is able to 를 주로 표현을 많이하는데
      2. 이로 계층구조가 불명확한 현실 세계의 개념을 명확히 적용할 수 있기에 그런 것으로 보임
  5. 기능을 향상시키는 안전하고 강력한 수단
    1. 래퍼 클래스 관용구(item 18)과 함께 사용시 인터페이스는 기능을 향상시키는 안전하고 강력한 수단이 됨
    2. 타입을 추상 클래스로 정의할 경우 그 타입에 기능을 추가하는 방법은 상속 밖에 없음
      1. 이때 상속해 만든 클래스는 래퍼 클래스보다 활용도가 떨어지고 깨지기 더 쉬움
    3. 인터페이스 메서드 중 구현 방법이 명확한 것이 존재한다면, 이는 디폴트 메서드로 제공할 수 있음
      1. 이는 책의 코드 21-1 removeIf 메서드를 보면됨
      2. Default 메서드를 제공할 때는 상속하려는 사람을 위한 설명을 @implSpec 자바 독 태그를 붙여 문서화해야 함
        (item 19)
        1. Defalt 메서드에 제약이 존재함
          1. equals, hashCode는 디폴트 메서드로 정의해서는 안됨
          2. 인터페이스는 인스턴스 필드를 가질 수 없음
          3. public이 아닌 정적 멤버를 가질 수 없음 (단, private 정적 메서드는 예외)
          4. 직접 개발하지 않은 인터페이스에 디폴트 메서드를 추가해서는 안 됨
  6. 인터페이스와 추상 골격 구현(skeletal implementatin) 클래스를 함께 재공해 인터페이스와 추상 클래스 장점을 모두 취할 수 있음
    1. 템플릿 메서드 패턴
      1. 인터페이스 = 타입 정의
      2. 필요시 디폴트 메서드 함께 제공
      3. 그리고 골격 구현 클래스는 나머지 메서드들까지 구현
    2. 위 처럼 구현할 경우 단순 골격 구현을 확장하는 것만으로 이 인터페이스를 구현하는데 필요한 일이 대부분 완료됨
      이를 위에 언급된 '템플릿 메서드 패턴'이라 함
    3. 골격 구현 클래스 = 'AbstractInterface'
      1. AbstractCollection, AbstractSet, AbstractList, AbstractMap 각각이 핵심 컬렉션 인터페이스의 골격 구현
    4. 골격 구현의 작성
      1. 인터페이스를 사라펴 다른 메서드들의 구현에 사용되는 기반 메서드 선정
      2. 기반 메서드들이 골격 구현에서 추상 메서드가 됨
      3. 기반 메서드들을 사용해 직접 구현할 수 있는 메서드를 모두 디폴트 메서드로 제공
        (단, equals, hashCode와 같은 Object 메서드는 제공해서는 안 됨)
      4. 만약 메서드 모두 기반 메서드와 디폴트 메서드가 된다면 골격 구현 클래스를 별도로 만들 이유가 없음
  7. 골격 구현은 기본적으로 상속해 사용하는 걸 가정하기에 아이템 19에서 이야기한 설계 및 문서화 지침을 모두 따라야 함
  8. 단순 구현은 골격 구현의 작은 변종임,. 이는 그대로 써도 되고 필요에 따라 확장해도 됨.

핵심 정리

  • 다중 구현용 타입으로 인터페이스가 가장 적합함
  • 복잡한 인터페이스라면 구현 수고를 덜어주는 골격 구현을 함꼐 제공한느 방법을 고려할 것
  • 골격 구현은 '가능한 한' 인터페이스의 디폴트 메서드로 제공해 그 인터페이스를 구현한 모든 곳에서 활용하도록 하는 것이 좋음
    • 가능한 한이라고 표현한 이유는 인터페이스에 걸려 있는 구현상의 제약 떄문에 골격 구현을 추상 클래스로 제공하는 경우가 더
      흔하기 때문