이펙티브 자바

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

호종이 2022. 2. 2. 21:44

자바가 제공하는 다중 구현 매커니즘은 인터페이스와 추상 클래스이다


자바가 제공하는 다중 구현 메커니즘은 인터페이스와 추상 클래스, 이렇게 두 가지다. 다만 둘 사이엔 아주 중요한 차이점이 존재한다.

 

  • 추상 클래스의 경우 타입을 구현하는 클래스는 반드시 추상 클래스의 하위 클래스가 되어야 한다
  • 인터페이스가 선언한 메서드를 모두 정의하고 규약을 잘 지킨 클래스라면 다른 어떤 클래스를 상속했든 같은 타입으로 취급된다.
  • 클래스는 여러 개의 인터페이스를 동시에 구현할 수 있다.

 

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


인터페이스는 상속의 관계가 아니고, 여러개를 구현할 수 있기 때문에 만약 새로운 기능이 추가된다면 기존 클래스에 손쉽게 추가할 수 있다.

인퍼테이스가 요구하는 메서드가 아직 없다면 추가하고, 클래스 선언에 implements 구문만 추가하면 된다. 

 

자바 플랫폼에서 Comparable, Iterable, AutoCloseable 인터페이스가 새로 추가됐을 때 표준 라이브러리의 수많은 기존 클래스들이 이 인터페이스들을 구현한 채 릴리스됐다. 

 반면에 기존 클래스 위에 새로운 추상 클래스를 끼워넣기는 어려운 게 일반적이다. 두 클래스가 같은 추상 클래스를 확장하길 원한다면, 그 추상 클래스는 계층 구조상 두 클래스의 공통 조상이어야 한다.

 

 

위 방식을 사용하면 새로 추가된 추상 클래스의 모든 자손이 이를 상속하게 된다. 

 

 

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


믹스인이란 클래스가 구현할 수 있는 타입으로, 믹스인을 구현한 클래스에 원래의 '주된 타입' 외에도 특정 선택적 행위를 제공한다고 선언하는 효과를 준다. 예를 들어 Comparable은 자신을 구현한 클래스의 인스턴스들끼리는 순서를 정할 수 있다고 선언하는 믹스인 인터페이스이다.

 대상 타입의 주된 기능에 선택적 기능을 혼합한다고 해서 믹스인이라 부른다.

 

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


타입을 계층적으로 정의하면 수많은 개념을 구조적으로 잘 표현할 수 있지만, 현실에는 계층을 엄격히 구분하기 어려운 개념도 있다. 예를 들어 가수 인터페이스와 작곡가 인터페이스가 있다고 해보자.

 

interface Singer {
	AudioClip sing(Song s);
}

interface Songwriter {
	Song compose(int chartPosition);
}

작곡도 하는 가수가 제법 많다. 이 코드처럼 타입을 인터페이스로 정의하면 가수 클래스가 Singer 와 Songwriter 를 모두 구현해도 전혀 문제되지 않는다. 심지어 singer 와 Songwriter 모두를 확장하고 새로운 메서드까지 구현한 제 3의 인터페이스를 정의할 수도 있다. 

 

public interface SingerSongwriter extends Singer,Songwriter {
	AudioClip strum();
    void actSensitive();
}

위와 같은 구조를 클래스로 만들려면, 가능한 조합 전부를 각각의 클래스로 정의한 계층구조가 만들어질 것이다. 속성이 n개라면 지원해야 할 조합의 수는 2^n 개나 된다.