[Java] Ch07_7. 인터페이스(interface)

토끼는 개발개발·2022년 2월 7일
0

Java

목록 보기
31/33
post-thumbnail

Chapter07. 객체지향 프로그래밍Ⅱ


✏️ 7. 인터페이스(interface)


7.1 인터페이스란?

인터페이스는 일종의 추상클래스이다. 추상클래스처럼 추상메서드를 갖지만 추상클래스보다 추상화 정도가 높아서 추상클래스와 달리 몸통을 갖춘 일반 메서드 또는 멤버변수를 구성원으로 가질 수 없다. 오직 추상메서드와 상수만을 멤버로 가질 수 있다.

추상클래스를 부분적으로만 완성된 '미완성 설계도'라고 한다면, 인터페이스는 구현된 것은 아무 것도 없고 밑그림만 그려져 있는 '기본 설계도'라 할 수 있다.

인터페이스도 추상클래스처럼 완성되지 않은 불완전한 것이기 때문에 그 자체만으로 사용되기 보다는 다른 클래스를 작성하는데 도움 줄 목적으로 작성된다.




7.2 인터페이스의 작성

interface 인터페이스이름 {
	public static final 타입 상수이름 =;
    public abstract 메서드이름(매개변수 목록);
}	

인터페이스를 작성하는 것은 클래스를 작성하는 것과 같다. 다만 키워드로 class 대신 interface를 사용한다는 것만 다르다. 그리고 interface에도 클래스와 같이 접근제어자로 public 또는 default를 사용할 수 있다.

일반적인 클래스의 멤버들과 달리 인터페이스의 멤버들은 다음과 같은 제약사항이 있다.

  • 모든 멤버변수는 public static final이어야 하며, 이를 생략할 수 있다.
  • 모든 메서드는 public abstract이어야 하며, 이를 생략할 수 있다.
    (단, static메서드와 디폴트 메서드는 예외(JDK1.8부터))

인터페이스에 정의된 모든 멤버에 예외없이 적용되는 사항이기 때문에 제어자를 생략할 수 있는 것이며, 편의상 생략하는 경우가 많다. 생략된 제어자는 컴파일 시에 컴파일러가 자동적으로 추가해준다.




7.3 인터페이스의 상속

인터페이스는 인터페이스로부터만 상속받을 수 있으며, 클래스와는 달리 다중상속, 즉 여러 개의 인터페이스로부터 상속을 받는 것이 가능하다.

interface Movable {
	/** 지정된 위치(x,y)로 이동하는 기능의 메서드 */
    void move(int x, int y);
}

interface Attackable {
	/** 지정된 대상(u)을 공격하는 기능의 메서드 */
    void attack(Unit u);
}

interface Fightable extends Movable, Attackable { }

클래스의 상속과 마찬가지로 자식 인터페이스(Fightable)는 부모 인터페이스(Movable, Attackable)에 정의된 멤버를 모두 상속받는다. 그래서 Fightable 자체에는 정의된 멤버가 하나도 없지만 부모 인터페이스로부터 상속받은 두 개의 추상메서드, move(int x, int y)와 attack(Unit u)을 멤버로 갖게 된다.




7.4 인터페이스의 구현


인터페이스도 추상클래스처럼 그 자체로는 인스턴스를 생성할 수 없으며, 추상클래스가 상속을 통해 추상메서드를 완성하는 것처럼, 인터페이스도 자신에 정의된 추상메서드의 몸통을 만들어주는 클래스를 작성해야 하는데, 그 방법은 추상클래스가 자신을 상속받는 클래스를 정의하는 것과 다르지 않다.

다만 클래스는 확장한다는 의미의 키워드 'extends'를 사용하지만 인터페이스는 구현한다는 의미의 키워드 'implements'를 사용할 뿐이다.

class 클래스이름 implements 인터페이스이름 {
	//인터페이스에 정의된 추상메서드를 구현해야 한다.
}

class Fighter implements Fightable {
	public void move(int x, int y) { /*내용생략*/ }
    public void attack(Unit u) { /*내용생략*/ }
}

만약 구현하는 인터페이스의 메서드 중 일부만 구현한다면, abstract를 붙여서 추상클래스로 선언해야 한다.

abstract class Fighter implements Fightable {
	public void move(int x, int y) { /* 내용생략 */ }
}

그리고 다음과 같이 상속과 구현을 동시에 할 수도 있다.

class Fighter extends Unit implements Fightable {
	public void move(int x, int y) { /*내용생략*/ }
    public void attack(Unit u) { /*내용생략*/ }
}

참고로 인터페이스의 이름에는 Fightable과 같이 '~을 할 수 있는'의 의미인 'able'로 끝나는 것들이 많은데, 그 이유는 어떠한 기능 또는 행위를 하는데 필요한 메서드를 제공한다는 의미를 강조하기 위해서이다. 모든 인터페이스의 이름이 반드시 'able'로 끝나야 하는 것은 아니다.




7.5 인터페이스를 이용한 다중상속


다중상속은 장점도 있지만 단점이 더 크다고 판단했기 때문에 자바에서는 다중상속을 허용하지 않는다.

인터페이스는 static상수만 정의할 수 있으므로 부모 클래스의 멤버변수와 충돌하는 경우는 거의 없고 충돌된다 하더라도 클래스 이름을 붙여서 구분 가능하다. 그리고 추상메서드는 구현 내용이 전혀없으므로 부모 클래스의 메서드와 선언부가 일치하는 경우에는 당연히 부모 클래스 쪽의 메서드를 상속받으면 되므로 문제되지 않는다.

그러나, 이렇게 하면 상속받는 멤버의 충돌은 피할 수 있지만, 다중상속의 장점을 잃게 된다. 만일 두 개의 클래스로부터 상속을 받아야 할 상황이라면, 두 조상클래스 중에서 비중이 높은 쪽을 선택하고 다른 한쪽은 클래스 내부에 멤버로 포함시키는 방식으로 처리하거나 어느 한쪽이 필요한 부분을 뽑아서 인터페이스로 만든 다음 구현하도록 한다.

예를 들어, 다음과 같이 Tv클래스와 VCR클래스가 있을 때, TVCR클래스를 작성하기 위해 두 클래스로부터 상속을 받을 수만 있으면 좋겠지만 다중상속을 허용하지 않으므로, 한 쪽만 선택하여 상속받고 나머지 한 쪽은 클래스 내에 포함시켜서 내부적으로 인스턴스를 생성해서 사용하도록 한다.


public class VCR {
	protected int counter;
    
    public void play() {
    	//Tape을 재생한다.
    }
    
    public void stop() {
    	//재생을 멈춘다.
    }
    
    public void reset() {
    	counter = 0;
    }
}

VCR에 정의된 메서드와 일치하는 추상메서드를 갖는 인터페이스를 작성한다.

public interface IVCR{
	public void play();
    public void stop();
    public void reset();
}

이제 IVCR 인터페이스를 구현하고 Tv클래스로부터 상속받는 TVCR클래스를 작성한다.
이때 VCR클래스 타입의 참조변수를 멤버변수로 선언하여 IVCR인터페이스의 추상메서드를 구현하는데 사용한다.

public class TVCR extends Tv implements IVCR {
	VCR vcr = new VCR();
    
    public void play() {
    	vcr.play(); // 코드를 작성하는 대신 VCR 인스턴스의 메서드를 호출
    }
    
    public void stop() {
    	vcr.stop();
    }
    
    public void reset() {
    	vcr.reset();
    }
}

IVCR인터페이스를 구현하기 위해서는 새로 메서드를 작성해야하는 부담이 있지만 이처럼 VCR클래스의 인스턴스를 사용하면 손쉽게 다중상속을 구현할 수 있다.
또한, VCR클래스의 내용이 변경되어도 변경된 내용이 TVCR클래스에도 자동적으로 반영되는 효과를 얻을 수 있다.

인터페이스를 새로 작성하지 않고도 VCR클래스를 TVCR클래스에 포함시키는 것만으로도 충분하지만, 인터페이스를 이용하면 다형적 특성을 이용할 수 있다는 장점이 있다.




7.6 인터페이스의 장점

  • 개발시간을 단축시킬 수 있다.
  • 표준화가 가능하다.
  • 서로 관계없는 클래스들에게 관계를 맺어 줄 수 있다.
  • 독립적인 프로그래밍이 가능하다.

예를 들어 한 데이터베이스 회사가 제공하는 특정 데이터베이스를 사용하는데 필요한 클래스를 사용해서 프로그램을 작성했다면 이 프로그램은 다른 종류의 데이터베이스를 사용하기 위해서는 전체 프로그램 중에서 데이터베이스 관련된 부분은 모두 변경해야할 것이다.

그러나 데이터베이스 관련 인터페이스를 정의하고 이를 이용해서 프로그램을 작성하면, 데이터베이스의 종류가 변경되더라도 프로그램을 변경하지 않도록 할 수 있다.

단, 데이터베이스 회사에서 제공하는 클래스도 인터페이스를 구현하도록 요구해야 한다. 데이터베이스를 이용한 응용프로그램을 작성하는 쪽에서는 인터페이스를 이용해서 프로그램을 작성하고, 데이터베이스 회사에서는 인터페이스를 구현한 클래스를 작성해서 제공해야 한다.

실제로 자바에서는 다수의 데이터베이스와 관련된 다수의 인터페이스를 제공하고 있으며, 프로그래머는 이 인터페이스를 이용해서 프로그래밍하면 특정 데이터베이스에 종속되지 않는 프로그램을 작성할 수 있다.




참고서적
자바의 정석(저자: 남궁성)


오늘의 한 줄

요즘 공부하고 있는 서블릿에서 인터페이스와 추상 개념이 나왔다.
객체지향프로그래밍 챕터를 공부하면서 객체지향언어의 장점을 보다 깊이 느꼈다.
인터페이스의 개념을 잘 이해하고 능숙하게 구현해보고 싶다.

profile
하이 이것은 나의 깨지고 부서지는 기록들입니다

0개의 댓글