인터페이스는 '현실 세계'의 '계약서'와 비슷하다. 계약서에는 무엇을 하라는 내용이 추상적으로 나와있다. 계약서 자체로는 실행되지 않는다. 작업자에 의해 구체적인 작업이 구현되어야 한다. 그래서 인터페이스를 다른 말로 '기본 설계도'라고 할 수 있다.
인터페이스와 추상 클래스의 용도가 비슷해보이는데 인터페이스를 사용하는 이유가 뭘까 ?
추상 클래스는 기본적으로 클래스이다. 하위 클래스는 상속을 하나만 허용하기 때문에 2개 이상의 클래스로부터 프로퍼티나 메서드를 상속받을 수 없다는 단점이 있다. 그리고 상위 클래스와 하위클래스에 강한 연관이 생기기 때문에 하위 클래스는 상위 클래스의 영향을 받는다. 예를 들어 상위 클래스가 정의한 내용이 불완전 하다면 그 상위 클래스를 상속받는 하위 클래스도 그대로 영향을 받는다. 그래서 상위 클래스가 수정되었을 때 하위 클래스를 일일히 확인하기 어려운 경우에 부작용을 발생시킬 수 있다.
우선, 인터페이스는 클래스가 아니다. 따라서 상속이라는 형태로 하위 클래스에 프로퍼티와 메서드를 전하지 앟는다. 이런 구현 클래스의 목적은 인터페이스가 제시한 메서드를 구체적으로 '구현'한다는데 있다.
interface Clickable {
fun press()
fun click()
}
// 인터페이스 상속
class Button: Clickable {
override fun click() {
println("Button Clicked")
}
override fun press() {
println("Button Press")
}
}
// 호출
fun main() {
val button = Button()
button.click()
button.press()
}
// 인터페이스 선언
interface Clickable {
fun click() // 일반 메서드 선언
fun showOff() = println("Clickable") // 디폴트 구현(본문)이 있는 메서드
}
interface b {
fun f() = println("B Interface f()") // 인터페이스는 기본적으로 open이다.
fun b() = println("B Interface b()")
}
open class A {
open fun f() = println("A class f ()")
fun a() = println("A class a()")
}
open class C: A(), b { // 쉼표를 사용해서 클래스와 인터페이스를 지정
override fun f() = println("C class f()")
open fun test() {
f ( ) // 현재 클래스의 f()
b ( ) // 인터페이스 b의 f()
super<A>.f() //A 클래스의 f()
super<b>.f() // B 클래스의 f()
}
}
class D: C()
fun main() {
val c = C()
c.test()
val d = D()
d.test()
}
interface InterfaceKotlin {
var variable: String
fun get()
fun set()
}
var KotlinImpl = object: InterfaceKotlin {
override var varibale: String = "variable"
override fun get() {
println("get")
}
override fun set() {
println("set")
}
}
fun main() {
KotlinImpl.get()
KotlinImpl.set()
}