Kotlin 기초 - 클래스 이해하기 2

지난번 포스팅에 이어~ 이번에는 코틀린 인터페이스에 대해 정리해보려 한다.

인터페이스

코틀린의 인터페이스는 추상 메소드 뿐 아니라 구현된 메소드(Java 8 의 default 메소드와 비슷)도 정의할 수 있다. 상태를 가질 수 없다는 점에서 abstract class 와는 다르다.

인터페이스 정의

인터페이스 정의는 interface 키워드를 사용하며, 여타 언어와 비슷한 모양이다.

interface Notifiable {  
   fun notify()
}

그리고, 아래와 같이 이 인터페이스를 구현할 수 있다.

class EmailNotifier: Notifiable {  
   override fun notify() = println("notify 메소드 구현")
}

자바에서는 implements 키워드를 사용하여 인터페이스를 구현하지만 코틀린은 :(콜론) 붙이고 인터페이스 이름을 적어 해당 인터페이스를 구현하는 것을 명시한다.

그리고, 상위 인터페이스의 메소드 또는 프로퍼티를 오버라이딩하기 위해 override 키워드를 꼭 붙여야 하는데, 실수로 상위 클래스의 메소드를 오버라이딩하는 경우를 막기 위해서이다.

위에서 잠깐 언급했듯이, 자바8부터 인터페이스에 메소드의 기본 구현을 제공할 수 있는데, 코틀린도 마찬가지다. 다만, 자바에선 default 키워드를 사용했다면 코틀린에서는 그럴 필요가 없다.

interface Notifiable {  
   fun notify() = println("default 함수 구현")
}

인터페이스 상속

코틀린도 자바와 마찬가지로, 하나의 인터페이스가 또 다른 인터페이스를 상속할 수 있다.

interface ExceptionHandler {  
   fun handleException(ex: Exception)
}

interface Notifier: ExceptionHandler {  
   fun send() = println("default 함수 구현")
}

자식 인터페이스는 부모 인터페이스의 함수를 오버라이딩하여 구현할 수 있다. 그리고, (당연하겠지만..) 이 인터페이스를 구현하는 클래스는 구현이 되어 있지 않은 함수에 대해서만 구현해도 된다.

interface Notifier: ExceptionHandler {  
   fun send() = println("default 함수 구현")
   override fun handleException(ex: Exception) =
      println("예외 처리 기본 구현")
}

class MailNotifier: Notifier {  
   override fun send() = println("메일 알림 실행")
}

오버라이딩 충돌 해결

두 개 이상의 인터페이스를 구현하려고 할 때, 가끔 이 인터페이스들 내 같은 이름의 메소드를 가지고 있는 경우가 있다.

interface Notifier {  
    fun send() = println("default 함수 구현")
}

interface MessageSender {  
    fun send()
}

class MailNotifier: Notifier, MessageSender {  
   // send() 를 오버라이딩 하지 않으면 오류!!
}

만약, 위의 경우와 같이 Notifier 인터페이스의 send 메소드는 default 구현이 되어 있는 상태이고, MessageSender 인터페이스의 send 는 default 구현이 없는 상태라고 하면, 이들 인터페이스를 구현하는 클래스에서는 당연하게도, send 메소드를 무조건 구현해줘야 한다.
MessageSender 인터페이스의 send 에 대한 구현 로직이 없으니 오류가 나는게 당연하다!

그럼, 아래와 같이, MessageSendersend 메소드가 default 메소드로 정의되어 있다면 어떻게 될까?

interface Notifier {  
    fun send() = println("Notifier 의 send 함수 구현")
}

interface MessageSender {  
    fun send() = println("MessageSender 의 send 함수 구현")
}

class MailNotifier: Notifier, MessageSender {  
   // send() 를 오버라이딩 하지 않으면 오류!!
}

이런 경우에도 오류가 발생하는데, 이때엔 코틀린 컴파일러가 어떤 인터페이스의 send 메소드를 사용할지 구분할 수 없기 때문이다.

컴파일 오류를 없애기 위해선, 아래 코드처럼, 어떤 인터페이스의 구현을 사용할지 명시적으로 선택할 수도 있고, 아예 새로운 동작을 구현해도 된다.

class MailNotifier: Notifier, MessageSender {  
   override fun send() {
      super<Notifier>.send()
      super<MessageSender>.send()
   }
   // 또는 아예 새롭게 구현
   // override fun send() = println("MailNotifier 의 send 함수 구현")
}

코틀린의 인터페이스에 대해 정리해보았다. 자바에 대해 이미 익숙한 프로그래머라면 지겨울 수 있는 내용이겠지만, 기초는 튼튼할수록 좋은거니깐.. 조바심 가지지 말고, 기초부터 확실히 내 것으로 만들고 가자!!