인터페이스 잘 사용하기

수박참외메론·2022년 12월 13일
0

자바가 제공하는 다중 구현 메커니즘은 interface 와 abstract class 가 있음.
그럼 일단 interface 와 abstract class 가 뭔지 알아보자

interface

abstract class

다중상속이 안되나?

다중 상속을 진행한다고 했을때 어떤 함수를 사용한다고 했을 때 어떤 부모의 함수를 가져다가 쓸지 몰라서 안됨.
다중상속이 안되는 이유
다중 구현은 가능
-> 근데그럼 다중구현을 할때 같은 함수를 override 한다고치면..? 껍데기만 있어서 가능?

이제(자바 8버전 이상?)는 두 메커니즘 모두 인스턴스 메서드를 구현형태로 제공할 수 있다.

인스턴스 메서드?

반드시 객체 생성해야만 호출 가능한 메서드
반대개념은 클래스 메서드로 메서드 앞에 static 키워드가 붙어있으면 클래스 메서드이다.

interface 를 사용해야되는 이유

  • 인터페이스의 규약을 잘 지킨 클래스라면 어떤 클래스를 상속했든 같은 타입으로 취급
  • 기존 클래스에도 손쉽게 새로운 인터페이스를 구현해넣을 수 있다.
  • 인터페이스는 mixin 정의에 안성맞춤이다.
  • 인터페이스는 계층구조가 없는 타입 프레임워크를 만들 수 있다.
    비교대상은 항상 "abstract class" 보다 낫다는 게 포인트.

기존 클래스에도 손쉽게 새로운 인터페이스 구현가능

interface를 구현하는건 그냥 interface가 구현하라고 요구하는 메서드만 추가하고 implements 절만 추가하면 된다. Java 플랫폼에서도 Comparable, Iterable, AutoClosable 인터페이스가 새로 추가되었을 때 표준 라이브러리의 수많은 기존 클래스가 이 인터페이스를 구현한 채 릴리스 되었었다.
이에 비해 Comparable 같은 interface를 abstract class 로 구현했다고 생각해보면, 수많은 클래스들이 공통 조상을 가지게 되지만, 또 다른 iterable 같은 기능을 추가하고 싶을때 이 또한 공통 조상이어야 하므로 불가능한 계층구조를 요구하게 된다.

mixin 정의에 적합

mixin 이란

클래스가 구현할 수 있는 타입으로, 믹스인을 구현한 클래스에 원래의 주된타입 외에도 특정 선택적 행위를 제공한다고 선언하는 효과..?

뭔소린지 모르겠다. 구글링을 해보았다.

객체지향 프로그래밍 언어에서 mix-in은 다른 클래스의 부모 클래스가 되지 않으면서 다른 클래스에서 사용할 수 있는 메서드를 포함한 클래스를 뜻한다.

상속이 가지는 is-a 관계와 대척되는 has-a 관계를 칭하는 말 같다. Interface는 해당 interface를 구현하는 클래스에게 어떤 클래스인지를 알려주기 보다는 어떤 기능을 가지고 있는지를 명시하기 때문에 has-a 관계라고 할 수 있다.

계층구조가 없는 타입 프레임워크 제작 가능

타입을 계층적으로 정의하면 수많은 개념을 구조적으로 잘 표현할 수 있지만, 현실에서는 계층을 엄격히 구분하기 힘든 개념도 있다.

public interface Singer {
	AudioClip sing(Song s);
}

public interface Songwriter {
	Song compose(int chartPosition);
}

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

interface 의 단점보완

  • Default Method
  • 추상 골격 구현 클래스 (skeletal implementation)

Default Method

인터페이스는 기능에 대한 선언만 가능하기 때문에, 실제 코드를 구현한 로직은 포함될 수 없었지만, 자바 8부터 default method가 나오며 이 법칙이 깨졌다.

interface MyInterface {
	default void printHello() {
    	System.out.println("Hello World");
    }
}

이런 식으로 사용할 수 있다.

이런 기능은 interface의 메서드 중 구현 방법이 명백한 것이 있으면 default method으로 제공하여 프로그래머들의 일감을 덜어 줄 수 있다.

default method의 제약

  • equals hashCode 같은 Object의 메서드는 default method으로 제공하면 안된다.
  • interface는 인스턴스 필드를 가질 수 없고, public 이 아닌 정적 멤버도 가질 수 없다.
  • 자기가 만든 interface 말고는 default method를 만들 수 없다.
    근데 내가봤을 때 첫번째 제약말고는 너무 당연한 것들이 아닌가.. 이는 interface의 제약이 아닌가 싶다.

Skeletal Implementation

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

골격 구현 클래스의 좋은 예시들로는 collection 프레임워크의 AbstractCollection AbstractSet AbstractList 등이 있다.

장점

무엇보다 abstract class처럼 구현을 도와주는 동시에 abstract class 로 정의할때 따라오는 심각한 제약에서 자유롭다ㅡㄴㄴ 점이다.

작성법

  1. 인터페이스를 잘 살펴 다른 메서드들의 구현에 사용되는 기반 메서드를 선정한다.
  2. 기반 메서드들을 사용해 직접 구현할 수 있는 메서드를 모두 default method으로 만든다.
  3. 1,2 단계를 거쳐 남은 메서드는 이 interface를 구현하는 골격구현클래스를 하나 만들어 남은 메서드들을 작성해 넣는다.

Map.Entry로 예시

간단한 예로 Map.Entry 인터페이스를 살펴보자.
Map.Entry 사용예시

한줄로 요약하자면 프로그래밍할때 자주 사용하는 map 자료구조의 iteration 작업의 최적화를 위해 나온 interface 라고 할 수 있다.

public abstract class AbstractMapEntry<K,V>
	implements Map.Entry<K,V> {
    
    @Override public V setValue(V value){
    	//구현
    }
    
    @Override public boolean equals(Object O){
    	//구현
    }
    
    @Override public int hashCode(){
    	//구현
    }
    
    @Override public String toString(){
    	return getKey() + "=" + getValue();
    }
}

골격 구현은 기본적으로 상속해서 사용하는걸 가정하므로 설계 및 문서화 지침까지 모두 따라야 한다.

정리

Abstract Class 보다는 Interface 를 사용하자.

profile
하루하루는 성실하게 인생전체는 되는대로

0개의 댓글