brunch

You can make anything
by writing

C.S.Lewis

by 이승현 Apr 02. 2018

클래스와 인터페이스

#18 추상 클래스보다는 인터페이스를 이용하자

Effective Java - 클래스와 인터페이스


#18 추상 클래스보다는 인터페이스를 이용하자


추상 클래스(abstract class)와 인터페이스(interface)은 아래와 같은 차이점이 있습니다.

(자바 1.8 미만 기준입니다.)

#01 추상 클래스 vs 인터페이스


이 차이점을 기반으로 왜 추상 클래스보다 인터페이스를 권장하는지에 대해 알아보겠습니다.




#01 기존 클래스들은 새로운 인터페이스를 구현하기 위해 쉽게 변경될 수 있다.


#02 implements & extends


기존 클래스들(B, C class)들은 새로운 인터페이스(A interface)를 구현하기 위해서 쉽게 변경될 수 있습니다.

기존 클래스 선언부에 implements를 추가하고, 인터페이스의 모든 메서드를 구현하면 됩니다.

class B implements A {
    // implements A interface's methods
}


하지만 추상 클래스를 이용한다면, 상속이 적합한지와는 상관없이 무조건 상속 계층이 발생하게 됩니다.

따라서 상속으로 인한 여러 문제점들이 발생할 수 도 있습니다.

class B extends A {
    // extends A abstract class's methods
}




#02 인터페이스는 믹스인(mixin)을 정의하는데 이상적이다.


믹스인은 클래스가 자신의 "본래 타입"에 추가하여 구현할 수 있는 타입으로서, 선택 가능한 기능을 제공하며, 그 기능을 제공받고자 하는 클래스에서 선언한다.


Effective Java 책에는 이렇게 정의되어 있는데, 사실 이해하기 힘듭니다.

쉽게 말해서 다른 클래스에서 이용할 기능(메서드)들을 포함한 클래스를 말합니다.


다른 클래스에서 이용할 메서드들을 추상 클래스에 정의하고 상속을 통해 구현할 수 있습니다.

하지만 만약 서브 클래스가 이미 다른 슈퍼 클래스를 상속받고 있다면, 다중 상속을 허용하지 않는 자바에서는 문제가 발생합니다.


따라서 다중 상속의 문제가 없는 인터페이스는 믹스인을 정의하는데 이상적입니다.





#03 인터페이스는 비계층적인 타입 프레임워크를 구축할 수 있게 해준다.


예를 들어, 개발자(developer)와 디자이너(designer)를 나타내는 인터페이스들이 있습니다.

public interface Developer {
    App develop(Guide g);
}

public interface Designer {
    Guide design(boolean isAndroid);
}


만약 디발자(디자이너 + 개발자)인 경우, 하나의 클래스에 Developer와 Designer 인터페이스를 모두 구현할 수 있습니다.

class Person implements Develper, Designer {
    App develop(Guide g) {
        return App;
    }
    
    Guide design(boolean isAndroid) {
        return Guide;
    }
}


그리고 Develper와 Designer 인터페이스를 모두 갖는 또 다른 인터페이스를 정의할 수 도 있습니다.

public interface Designvelopment extends Developer, Designer {
    // add something
}

class Person implements Designvelopment {
   App develop(Guide g) {
        return App;
    }
    
    Guide design(boolean isAndroid) {
        return Guide;
    }
}




#04 인터페이스는 안전하고 강력한 기능 향상을 가능하게 해준다.


인터페이스는 구현된 메서드가 없다는 단점이 있습니다.

인터페이스와 추상 클래스의 장점을 결합시킨 골격 구현(skeletal implementation) 추상 클래스를 통해 이를 보완할 수 있습니다.

인터페이스는 타입을 정의하고, 골격 구현 클래스는 이를 구현하는 모든 일을 맡게 됩니다.

이미 알려진 골격 구현 추상 클래스에는 AbstractCollect, AbstractList 등이 있습니다.


예를 들어, 아래 코드는 List 인터페이스를 구현해서 반환해주는 static 메서드입니다.

new 연산자를 통해 List 인터페이스의 객체를 생성해주는데, 이런 경우엔 List 인터페이스의 모든 메서드를 직접 구현해줘야 하는 단점이 있습니다.

#03 List static method


AbstractList 골격 구현 추상 클래스를 이용하면, List 인터페이스를 간단하게 구현할 수 있습니다.

#04 List static method


AbstractList 클래스는 List 인터페이스를 구현하고 있으며, 공통적인 메서드도 이미 구현되어 있습니다.

필요시 메서드를 오버라이드 하여 이용할 수 있기 때문에 인터페이스만을 이용한 구현보다는 이점이 있습니다.

#05 AbstractList class




추상 클래스 장점


인터페이스보다는 추상 클래스를 진화시키는 게 훨씬 더 쉽습니다.


#06 interface & abstract class


만약 인터페이스에 새로운 메서드를 추가한다면, 이를 구현하는 모든 클래스에서 직접 이 메서드를 구현해야 합니다.

하지만 추상 클래스에 새로운 메서드를 추가/구현한다면, 이를 상속하는 모든 서브 클래스에서는 직접 이 메서드를 구현하지 않고 바로 이용할 수 있습니다.




추상 클래스에 비해 인터페이스가 가진 여러 장점들이 있습니다.

하지만 단점도 있기에, 인터페이스를 설계할 때는 신중하고 철저히 테스트를 해야 합니다.



매거진의 이전글 클래스와 인터페이스
브런치는 최신 브라우저에 최적화 되어있습니다. IE chrome safari