인터페이스는 왜 필요할까? 그리고 무엇일까?

Interface의 사전적 의미

  • inter-(상호간의) + -face(면) = interface
  • 접해있는 두 물체나 공간 사이의 경계
  • 사용자는 스위치를 키는 버튼에 집중
    • 이걸 누르면 어떤 일이 일어날지를 앎 (what)
    • 어떻게 그런일이 일어나는지는 모름 (how)
  • 실제 동작은 구현 공간에서 일어남
    • 배선의 연결
    • 사용자는 잘 알지 못하는 공간
    • 구현자만 알고 있음
  • 이미 알고 있는 개념 = 함수
    • 함수는 블랙박스임: 호출자는 내부가 어떻게 도는지 이해하려 하지 않는다.
    • 함수명과 반환형: 어떤 동작을 하는지 알려줌
    • 함수 매개변수: 어떤 데이터를 전달해야 함수가 동작하는지 알려줌
    • 그래서 함수 signature를 interface라 부르기도 함
      • 컴퓨터 분야에서 인터페이스란 매우 다양한 것을 의미함

함수 선언 vs 함수 구현

  • 함수 선언 == 함수 signature == interface
  • c와 같은 언어에서는 이해하기 쉬울 것
    • 선언과 구현이 분리되어 있으므로
  • 그런데 함수 signature, interface만 존재하는 경우도 있었다.
  • 함수 포인터 매개변수는 signature만 지정
void register error handler (void (*handler) (const char* msg));
void log error(const char* msg);

static void (*s_handler) (const char*) = NULL;

void register error_handler (void (*handler) (const char* msg)) // 여기
{
    s handler = handler;
}

void log error(const char* msg)
{
    if (s_handler != NULL) {
        s_handler (msg) ;
    }
}
  • void (*handler) (const char* msg) 부분은 함수 signature만 있고 구현이 없다.
  • OO에서 다형성도 이와 같이 동작한다.
  • 결국 다형성은 구현체에 있는 함수를 호출하는 것이기 때문에, 거의 같은 방식이라 생각할 수 있다.

함수 포인터 매개 변수 vs. 클래스 매개변수

  • 그러면 이러한 의문이 들 수 있다.
  • "내가 필요한 건 실제로 구현한 메서드 함수만 알면되는데, 다형성을 사용하면서 다른 메서드들까지 딸려오게 되네..?"
  • "함수 포인터가 더 나은 것 아닌가?"
함수 포인터 매개변수클래스 매개변수
- 어떤 함수 구현도 signature만 맞다면 다 받아줌- 부모 클래스를 상속한 클래스면 다 받아줌
- 그 중 다형성 메서드 하나를 호출
- 실질적으로 C의 함수 포인터처럼 작동
- 근데 배보다 배꼽이 더 큰..?
  • 아니 그러면 추상 클래스에서 메서드를 싹다 abstract로 만들면 되지 않을까?
  • 일단 함수포인터와 완전히 같게 하기 위해서는 추상클래스의 메서드를 한개로 제한하고, 그 메서드를 abstract로 만들자.
  • 그러면 상속하는 쪽에서 무조건 구현해야 하니까, 그런 추상클래스 자체를 인자로 넘기는 행위는 곧 함수 포인터와 완전히 같게 된다.
  • 여기서 abstract 메서드의 개수를 늘리는 것은 결국 함수포인터 여러개를 한번에 주는 것과 같으니 사용할만 할 것

OO 개념과 인터페이스

  • 구조체: 데이터만 모아놓았던 것
  • 클래스: 데이터와 동작을 모아놓은 것
  • 순수 추상 클래스: 구현은 빼고 동작만 모아놓은 것 == Interface
  • Interface
    • 어떠한 상태도 없음
    • 동작의 구현도 없음
    • 동작의 signature만 있음

Interface

public abstract class LoggerBase {
    public abstract void log(String message);
}

public interface ILoggable {
    void log(String message);
}
  • class -> interface
  • abstract 지우기
    • interface는 자체가 추상적
  • method는 항상 public
    • 함수 포인터와 같은 개념인데 막아둔다는 것은 이상함
    • 그런데 요즘 언어에서는 다른 ACL도 들어갈 수 있어짐
    • 절대적인 것은 아니고, 이러한 흐름이 있었다 정도로 이해하는 것이 좋을듯
  • extends를 implements로 바꿈
    • :만을 사용하는 경우도 있음
  • interface 구현하지 않으면 컴파일 오류

Override의 문제

  • 오타났을 때, 동작은 하나 의도대로 동작하지 않을 수 있음
  • shoutshuot로 썼는데 이걸 확인못하고 넘어가면 삽질하게 되는 거임
  • 그럼 이런 오타를 방지하기 위해 추상 클래스를 인터페이스로 바꾸어야 하는가?
  • 그건 아니다.
  • override를 하는 경우 명확하게 이를 수행한다는 keyword를 추가하면 된다.
  • 즉, override하는 경우 override와 같은 키워드를 통해서만 가능하도록 제약을 걸어버린다.
  • 이렇게 되면, 코드 작성자는 override 없이 수행할 수 없으므로 보다 안전한 코딩이 가능해진다.
  • 자바에서는 annotation이라는 것을 사용한다. 이는 언어의 일부로 존재하는 것이 아니다. (@Override)

Java Annotation

  • 프로그램에 대한 metadata를 제공
    • 프로그램의 일부가 아니어서 코드 실행에는 아무 영향을 안 미침
  • 용도
    • 컴파일러에게 정보를 제공 (@Deprecated, @Override)
    • 컴파일, 혹은 배포 중에 어떤 처리를 할 수 있음

Interface의 접근 제어자

  • 추상 메서드는 protected를 붙일 수 있다.
  • 그 때문에 외부에서 호출은 못해도 자식 클래스가 구현하도록 강제할 수 있다.
  • 왜 인터페이스는 안되게 해두었을까?

왜 인터페이스는 public method만 가능할까?

  • 개념상으로 인터페이스는 두면이 맞닿는 면을 말한다.
  • 그렇기에 그 사이에서 필요한 모든 것들을 정의하는 것이 옳다.
  • 여기서 특정 메서드는 연결점으로 사용하지 않겠다는 것이 의미적으로 이상하다.
  • 이게 일반적인 얘기다.
  • 주류 언어에서는 public으로 강제하니 동의하지 않아도 방법은 없다.
  • C의 헤더파일과 비슷하다고 보면 이해가 쉽다.
    • header file을 include한 어느곳에서든 사용할 수 있다.

Interface의 이름

  • 앞에 붙은 I는 무엇인가? (ILoggable)
    • Interface의 약자
  • -able과 같은 형태로 붙일 수도 있음
    • 인터페이스는 "무언가를 할 수 있다"의 표현이기 때문에

Interface는 다중 상속의 위험이 없다

  • 다중 상속의 문제는 구현이 각각 존재하기 때문에 어떤 것을 선택할지 모른다에 있다.
    • 죽음의 다이아몬드
    • A가 이름이 같은 메서드의 B, C를 다중상속한다면 구현이 두개라 어떤걸 선택할지 모른다.
  • 이런 문제에서 인터페이스는 자유롭다.
  • 인터페이스는 구현이 없기 때문에, A에서 구현을 해야하고 이 때 이름이 같다면 하나로 퉁칠 수 있게 된다.

어떻게 상속해도 Interface의 구현은 하나뿐

  • Interface에서 선언한 메서드의 구현은 Class에서 생김
  • Class 다중 상속은 불가능
  • 따라서 한 클래스안에서 Interface의 구현은 딱 하나만 존재
  • 그래서 다중 상속의 해결법으로 많이 사용함
    • 단, 단순히 그 용도는 아님

깊은 복사 & 얕은 복사

  • java에서는 clone()을 사용함
  • 이 방법이 어렵다 생각하여 복사 생성자 방법도 사용함
    • public init(other point: Point)
    • 자기 자신의 자료형을 받아 자신을 리턴함
    • 내부적으로 복사하는 코드를 만들어 사용
    • swift의 경우에는 기본 자료형이 struct로 되어있어 이 문제에서 약간더 자유롭긴함

정리

  1. 함수 포인터처럼 인터페이스를 사용한다. (구현과 선언의 분리)
  2. 다중 상속의 대안으로 인터페이스를 사용한다.

핵심은 다형성, 다형성 없는 인터페이스는 의미가 없다.

Reference

profile
Goal, Plan, Execute.

0개의 댓글