Kotlin 인터페이스
인터페이스 (interface)
인터페이스는 추상 클래스와 동일하게 자신을 인스턴스화 할 수 없고, 구현해야 할 속성과 메소드를 정의한다. 추상 클래스가 “상속"을 위한 것이라면, 인터페이스는 서브 클래스로써의 “기능"을 정의하는 것으로, 하나의 서브 클래스가 여러 인터페이스를 구현할 수 있다.
Kotlin의 인터페이스는 추상 메소드와 구현이 포함될 수 있다. 추상 클래스와 다른점은 프로퍼티의 상태 정보를 저장할 수 없다는 것이다.
다시 말하자면, 인터페이스에서는 프로퍼티의 초기화(initializer)를 할 수 없다.
interface User {
val name = "devkuma" // Error: 속성 초기화는 인터페이스에서 허용되지 않는다.
}
인터페이스는 interface
키워드를 사용하여 정의된다.
interface MyInterface {
fun bar()
fun foo() {
// optional body
}
}
인터페이스 구현 (Implementing Interfaces)
한개의 클래스나 객체는 한개 이상의 인터페이스를 가질 수 있다. 인터페이스를 상속 받으면 반듯이 인테페이스를 구현해야 한다.
class Child : MyInterface {
override fun bar() {
// body
}
}
인터페이스의 프로퍼티 (Properties in Interfaces)
인터페이스에서 속성을 선언할 수 있다. 인터페이스에 선언된 속성은 추상화(abstract) 하거나 접근자(accessor)를 구현해야 한다. 인터페이스에서는 프로퍼티를 초기화할 수 없으므로 인터페이스에 선언된 접근자는 이를 참조할 수 없다.
interface MyInterface {
val prop: Int // abstract
val propertyWithImplementation: String
get() = "foo"
fun foo() {
print(prop)
}
}
class Child : MyInterface {
override val prop: Int = 29
}
인터페이스 상속 (Interfaces Inheritance)
인터페이스는 다른 인터페이스를 상속할 수 있다. 따라서 상속하는 인터페이스에서는 상위 인터페이스의 멤버를 구현을 하거나 메소드 및 프로퍼티를 새로 선언할 수 있다.
이러한 인터페이스를 구현하는 클래스는 최종적으로 구현이 되지 않은 맴버들만 구현하면 된다.
interface Named {
val name: String
}
interface Person : Named {
val firstName: String
val lastName: String
override val name: String get() = "$firstName $lastName"
}
data class Employee(
// implementing 'name' is not required
override val firstName: String,
override val lastName: String,
val position: Position
) :
인터페이스 Named
의 name: String
이 Person 에서 구현이 안되었다면 Employee
에서는 구현을 해야 한다.
오버라이딩 충돌 해결 (Resolving overriding conflicts)
여러 인터페이스를 상속을 받아 구현을 해야 할 때, 구현해야 할 메소드가 상속되는 경우가 있다.
interface A {
fun foo() { println("A") }
fun bar() // abstract
}
interface B {
fun foo() { println("B") }
fun bar() { println("bar") }
}
class C : A {
override fun bar() { println("bar") }
}
class D : A, B {
override fun foo() {
super<A>.foo()
super<B>.foo()
}
override fun bar() {
super<B>.bar()
}
}
fun main() {
val c = C()
c.foo()
c.bar()
println()
val d = D()
d.foo()
d.bar()
}
인터페이스 A와 B는 모두 foo()
와 bar()
함수를 선언하였다. A, B 둘 다 foo()
를 구현하였고, A는 bar()
를 구현하지 않았지만, B에서는 구현하였다.
클래스 C에서는 인터페이스 A만 상속하였으므로 bar()
만 구현하면 된다.
클래스 D에서는 인터페이스 A, B를 상속하고 있으므로 중복되는 메소드들에 대한 명확한 처리가 필요하다. 이는 한번만 구현된 bar()
함수와 여러번 구현된 foo()
함수 모두 해당된다.