[Java] 추상 클래스보다는 인터페이스

1 분 소요

추상 클래스 상속의 문제점

  • 상속용 클래스는 오버라이딩할 수 있는 메서드가 내부적으로 어떻게 이용되는지 문서로 남겨야 한다. 클래스를 상속한 클라이언트가 특정 메서드를 오버라이딩 한 경우 부모 클래스의 특정 메서드에서 해당 메서드를 내부 호출한다면 의도치 않은 오류가 생길 수 있기 때문이다.
  • 부모 클래스의 설계가 바뀌면 자손 클래스에도 의도치 않은 영향을 미치게 되고 부모 클래스에 설계 결함이 있다면 그대로 자손 클래스에 승계된다.
  • 효율성을 위해 자손 클래스에서 오버라이딩이 가능하도록 protected 메서드를 제공해야 할 수도 있다.
  • 부모 클래스의 구현이 자손에게 공개되어 캡슐화 원칙이 깨지며 자손 클래스가 부모 클래스에게 강하게 결합하게 된다. 또한 클라이언트가 부모 클래스의 메서드에 직접 접근하여 자손 클래스의 불변식을 해칠 수도 있다.
  • 자바는 다중 상속을 허용하지 않으며 여러 개 클래스의 공통된 분모를 추상화하기 위해서는 계층 구조가 매우 복잡해질 수 있다.

기능 확장

추상 클래스의 상속과 달리 기존 클래스에도 손쉽게 새로운 인터페이스를 구현해 넣을 수 있다. 또한 믹스인(mixin) 정의에 안성맞춤이다. 믹스인은 대상 타입의 주된 기능에 더하여 선택적 부가 기능을 혼합할 수 있다. 예를 들어 Comparable 인터페이스를 구현하게 되면 이를 구현한 클래스 인스턴스와 비교하여 순서를 정할 수 있다.

계층구조의 파괴

기능을 기준으로 정의된 인터페이스 또는 다른 인터페이스를 (다중) 상속한 인터페이스를 이용하면 복잡한 계층구조 없이 필요한 기능을 구현하고 타입 프레임워크를 만들 수 있다.

템플릿 메서드 패턴

자바 8버전부터 인터페이스도 디폴트, static 메서드를 지원한다. 따라서 기반 메서드로 구현할 수 있는 모든 메서드를 디폴트 메서드로 제공한다. 기반 메서드는 인터페이스를 상속한 추상 골격 클래스에서 추상 메서드가 되며 기반 메서드나 디폴트 메서드로 구현하지 못한 메서드는 골격 클래스에서 구현한다. 이를 통해 클라이언트는 추상 클래스를 상속하고 단 몇 개의 추상 메서드를 구현함으로써 기능 이용이 가능해진다.

주의점

  • 디폴트 메서드는 @ImplSpec 자바독 태그를 이용해서 문서화해야 한다.
  • 부모 클래스와 인터페이스의 디폴트 메서드가 충돌할 경우 전자가 우위에 있으므로 Objectequal, clone과 같은 메서드는 디폴트로 제공해서는 안 된다.
  • 직접 만든 인터페이스가 아니라면 디폴트 메서드를 추가할 수 없다.

댓글남기기