AiPE

인터페이스(Interface)란? 본문

[XiBBaL] Study/Java

인터페이스(Interface)란?

Oshimaker XiBBaL 2024. 5. 7. 14:28
반응형

객체지향에서의 인터페이스가 무엇인지에 대해 내가 들었던 자바 강의 선생님께서 좋은 설명을 해 주셔서 이를 그대로 가져왔다.

 

"객체지향은 프로그램의 각 부분을 부품화하는 설계 방식이라고 할 수 있다."는 명제를 전제하고 읽어보자.

 


잘 만들어진 부품이라면 부품과 부품을 서로 교환 할 수 있어야 한다. 

예를 들어보자.

집에 있는 컴퓨터에 A사의 모니터를 연결하다가 B사의 모니터를 연결 할 수 있다. 또, 집에 있던 모니터에 A사의 컴퓨터를 연결해서 사용하다가 새로운 컴퓨터를 구입하면서 B사의 컴퓨터를 연결 할 수 있다. 모니터와 컴퓨터는 서로가 교환관계에 있는 것이다.

이것은 모니터와 컴퓨터를 연결하는 케이블의 규격이 표준화 되어 있기 때문에 가능한 일이다. 

컴퓨터와 모니터를 만드는 업체들은 HDMI의 규격을 공유한다. 모니터 입장에서는 컴퓨터가, 컴퓨터 입장에서는 모니터가 어떤 식으로 만들어졌는지는 신경쓰지 않는다. 각각의 부품은 미리 정해진 약속에 따라서 신호를 입, 출력하고, 연결점의 모양을 표준에 맞게 만들면 된다.

이러한 연결점을 인터페이스(interface)라고 한다.

HDMI 케이블의 연결점은 특유의 생김새가 있다. 만약 HDMI 케이블을 랜선을 연결하는 구멍에 연결하려고 한다면 어떻게 될까? 동작하지 않을 뿐 아니라 연결 자체가 되지 않는다. 인터페이스란 이질적인 것들이 결합하는 것을 막아주는 역할도 하는 것이다. 즉 인터페이스는 부품들 간의 약속이다. 

[출처] https://opentutorials.org/course/1223/5399

 

위 설명을 소프트웨어적으로 풀어보면 '인터페이스'는 하나의 객체(부품)입장에서 다른 객체(부품)의 내부를 알지 못해도 그 입출력을 사용할 수 있도록 하는 규약이자 표준이다.

 

즉, 객체와 그 객체를 통한 인스턴스를 생성하기 이전에 그 객체들이 어떠한 것들을 어떻게 가져야 하는지 미리 규정해 둔 것이 인터페이스라고 할 수 있다.

 

이를 코드로 나타내면 아래와 같이 나타낼 수 있다.

// 인터페이스 정의
interface Animal {
    void eat();  // 추상 메서드 선언
    void sleep();
}

// Animal 인터페이스를 구현하는 구현 클래스
class Dog implements Animal {
    @Override
    public void eat() {
        System.out.println("개가 먹이를 먹습니다.");
    }

    @Override
    public void sleep() {
        System.out.println("개가 잠을 잡니다.");
    }

    public void bark() {
        System.out.println("멍멍!");
    }
}

class Cat implements Animal {
    @Override
    public void eat() {
        System.out.println("고양이가 생선을 먹습니다.");
    }

    @Override
    public void sleep() {
        System.out.println("고양이가 깊은 잠에 듭니다.");
    }

    public void purr() {
        System.out.println("야옹~");
    }
}

// 메인 클래스
public class AnimalDemo {
    public static void main(String[] args) {
        Animal dog = new Dog(); // 인터페이스 타입으로 구현 객체를 참조
        dog.eat();  // Dog 클래스의 eat() 메서드 호출
        dog.sleep(); // Dog 클래스의 sleep() 메서드 호출

        Animal cat = new Cat(); // 인터페이스 타입으로 구현 객체를 참조
        cat.eat();  // Cat 클래스의 eat() 메서드 호출
        cat.sleep(); // Cat 클래스의 sleep() 메서드 호출

        // dog.bark(); // 컴파일 오류: Animal 타입으로는 bark() 메서드에 접근할 수 없음
        // cat.purr(); // 컴파일 오류: Animal 타입으로는 purr() 메서드에 접근할 수 없음
    }
}

 

위 코드를 보면 Animal이라는 인터페이스를 통해 모든 Animal 인터페이스를 구현하는 객체들에 대해 eat과 sleep이라는 메서드 구현을 강제하고 있는 것을 볼 수 있다.

 

잠을 안 자거나 먹지 않는 Animal은 없으므로, 개발자는 먹지 않거나 자지 않는 괴생명체를 잘못 구현하는 경우를 방지하기 위해 모든 Animal에 강제로 eat과 sleep을 구현하도록 장치해둔 것이다.

 

이제 인터페이스가 프로그래밍적으로 무엇인지 조금 더 딱딱하게 정의해보면, "인터페이스는 추상 메서드와 상수만을 가지는 추상화된 형태의 클래스이다."라고 할 수 있다.

 

인터페이스 내의 모든 메서드는 추상 메서드로 선언되며, 일반적으로 상수(static final 변수)를 선언할 수 있다.

 

 

 

 

이제 이쯤 되면 "추상 클래스와 인터페이스가 뭐가 다른가?", "둘이 하는 역할은 동일한것같은데 왜 굳이 다르게 부를까?"라는 의문이 든다.

https://xibbal-lab.tistory.com/78 ( ← 추상 클래스의 정의가 궁금하면 참고 )

 

추상 클래스(Abstract Class) 및 추상 메서드(Abstract Method)의 정의와 활용

1. 추상 클래스(Abstract Class)와 추상 메서드(Abstract Method)의 정의 추상 클래스(Abstract Class)는 하나 이상의 추상 메서드(Abstract Method)를 포함하는 클래스이다. 추상 메서드는 선언만 되어 있고 구현이

xibbal-lab.tistory.com

 

이를 해결해보자.

 

 

 

2. 추상 클래스(Abstract Class)와 인터페이스(Interface)의 비교

인터페이스와 추상 클래스는 자신을 상속하는 모든 클래스들에 대해 특정 메서드에 대한 설명(정의)를 강제한다는 공통점이 존재한다. 따라서, 하는 역할도 "메서드 구현의 강제"라는 점에서 굉장히 비슷하다.

 

하지만 인터페이스와 추상 클래스는 존재 목적과 활용에 약간의 관점 차이가 존재한다.

 

만약, 우리가 키보드 소프트웨어(펌웨어)를 짜는 상황이라고 하자.

 

사용자가 "ㄱ"키를 누르면 소프트웨어는 컴퓨터에 "ㄱ"을 전달한다. (실제로는 더 복잡한 과정이지만 이해의 편의를 위해 이렇게 가정하자.)

 

대부분의 키는 "ㄱ" "ㄲ" "#" "2" 등 고정적인 키의 값을 가지고 있지만, 요즘 키보드는 사용자가 직접 그 키가 무슨 문자를 의미할지에 대해 지정할 수 있는 "핫키(즐겨찾기 키)" 기능을 제공한다.

 

이러한 경우, 개발자는 핫키를 제외한 모든 키에 대해서는 일반적인 메서드("ㄱ"을 입력받으면 "ㄱ"을 전달한다.)를 사용하면 된다. 하지만 핫키의 경우 사용자가 무엇을 지정할 지 모르기 때문에 비워둘 수밖에 없다. 핫키를 눌렀지만 이 정보가 컴퓨터에 전달되지 않는 경우가 있어서는 안 되므로, 핫키또한 어떠한 기능을 가질 것인데, 그 기능은 나중에 정의해야 하는 상황인 것이다.

 

이럴 때 사용하는 것이 추상 클래스이다. 추상 클래스는 일반적인 메서드를 정의하고, 추상 메서드를 함께 정의해 둘 수 있기 때문이다. 우리가 만들던 키보드 소프트웨어의 경우 키보드 소프트웨어 클래스를 추상 클래스로 정의하고, 핫키를 제외한 경우는 일반 메서드, 핫키는 추상 메서드로 정의해두면 된다.

 

반면 인터페이스는 인터페이스 클래스 내에 일반 메서드를 정의할 수 없다.

 

그러면 추상 클래스가 인터페이스의 상위호환일텐데, 인터페이스를 왜 쓸까?

 

이를 이해하기 위해서는 다중 상속의 모호성에 대해 알아야 한다. 

 

다중 상속은 부모 클래스가 두개 이상인 상황을 의미한다. 이러한 상황에서 자식 클래스의 인스턴스에서 부모 클래스의 메서드 right( )를 호출했다고 해 보자. 이 때, 부모 클래스 1에서도 right( )이 정의되어 있고, 부모 클래스 2에서도 right( )이 정의되어 있다. 근데 이 둘의 정의가 다르다. 이런 상황이라면 자식 클래스는 부모 클래스 1과 2 중 어떤 클래스의 right( )을 실행해야 할까? 이게 바로 다중 상속의 모호성이다.

 

Java는 이러한 다중 상속의 모호성을 아예 근원부터 없애기 위해 다중 상속을 하지 못하게 만들어졌다. 따라서 Java에서는 어떤 하위 클래스의 직계 상위 클래스는 하나뿐이다.

 

그런데, 이렇게 해놓고 보니 다중 상속이 모호하기는 하지만 편리할 때도 있어 아쉽다.

다중 상속을 막으면서도 다중 상속과 비스무리하게 할 수 있는 샛길을 터 두기 위해 탄생한 것이 인터페이스이다.

 

따라서 인터페이스는 서로 다른 상위 클래스에서 하나의 하위 클래스에 어떠한 메서드 구현을 강제하고 싶을 때 사용한다. 어차피 실질적인 구현은 하위 클래스에서 할 것이므로, (상위) 인터페이스에서 구현을 요구하는 메서드 이름이 겹쳐도 실질적인 정의는 1개이기 때문에 문제가 발생하지 않기 때문이다.

 

추상 클래스와 인터페이스의 공통점과 차이점을 정리하면 아래와 같다.

 

  추상 클래스(Abstact Class) 인터페이스(Interface)
공통점 하위 클래스에 대한 메서드 구현의 강제, 메서드 구현 보장
차이점 1. 클래스 안에 추상 메서드가 하나 이상 포함되거나 Abstract 키워드가 사용된 경우

2. 다중 상속 불가능
1. 인터페이스 내의 모든 메서드는 추상 메서드여야 함 (일반 메서드 포함 불가능)

2. 다중 상속을 비스무리하게 할 수 있음

 

1. 인터페이스는 완전히 추상화된 (즉, 추상 메서드만 존재하는) 클래스이며, 다중 상속을 지원하고 특정 동작을 강제한다.
2, 추상 클래스는 일부 메서드가 구현된 (추상+일반) 클래스이며, 인스턴스를 직접 생성할 수 없고 상속을 통해 사용된다.

 

일반적으로, 인터페이스는 다양한 타입의 객체를 사용하고 특정 동작을 보장하기 위해 사용되고, 추상 클래스는 상속을 통해 공통된 동작을 공유하고 확장하기 위해 사용된다고 정리할 수 있다.

 

추상 클래스와 인터페이스의 차이에 대해 참고해볼 만한 글이 있어 가져와보았다.

https://brunch.co.kr/@kd4/6

 

자바의 추상 클래스와 인터페이스

추상 클래스와 인터페이스의 차이 | 추상 클래스(Abstract class)와 인터페이스(Interface)의 차이 및 존재 이유를 설명해주세요. 클래스는 크게 일반 클래스와 추상 클래스로 나뉘는데 추상 클래스는

brunch.co.kr

 

반응형