devlog of ShinJe Kim

[Kotlin] 인터페이스

|

인터페이스(Interfaces)

이 글은 코틀린 공식문서를 공부하며 번역한 글입니다. 틀린 부분이나 어색한 부분을 댓글로 알려주시면 감사하겠습니다.

코틀린 인터페이스에서는 추상메소드와 구현이 있는 메소드 모두 선언할 수 있습니다. 인터페이스와 추상클래스와 다른 점은 인터페이스는 상태(필드)를 저장할 수 없다는 것입니다. 인터페이스는 추상적이거나 accessor implementations를 제공하는 프로퍼티만을 가질 수 있습니다.

interface MyInterface{
    fun bar()
    fun foo(){
        // optional body
    }
}

인터페이스 구현하기(Implementing Interfaces)

인터페이스를 사용하는 방법은 자바보다 간편합니다. 자바에서는 [class] implements [interface]의 형식으로 구현했지만 코틀린에서는 아래와 같이 클래스 이름 뒤에 콜론(:)을 붙인 뒤 인터페이스 이름을 적으면 됩니다.

class Child : MyInterface{
    override fun foo(){
        // body
    }
}

인터페이스의 프로퍼티(Properties in Interfaces)

인터페이스에서 프로퍼티를 사용할 수 있습니다. 인터페이스에서 선언된 프로퍼티는 추상 프로퍼티이거나 접근자로 구현할 수 있어야 합니다. 인터페이스에 선언된 프로퍼티는 backing fields를 가질 수 없으므로 접근자가 참조할 수 없습니다.

interface MyInterface{
    val prop: Int // abstract

    val propertyWithImplementation: String
        get() = "foo"
    
    fun foo() {
        print(prop)
    }
}

class Child : MyInterface{
    // 코틀린에서는 override 변경자를 꼭 사용해야합니다. 
    override val prop: Int = 29 
}

인터페이스 상속(Interface 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
) : Person

오버라이딩 충돌 해결하기(Resolving overriding conflicts)

상위 타입(supertype)을 많이 선언하면 같은 메소드를 한 번 이상 상속 받는 것처럼 보입니다.

interface A {
    fun foo() { print("A")}
    fun bar()
}

interface B {
    fun foo() { print("B")}
    fun bar() { print("bar")}
}

class C : A {
    override fun bar() { print("bar")}
}

class D : A, B {
    override fun foo() {
        super<A>.foo()
        super<B>.foo()
    }

    override fun bar() {
        super<B>.bar()
    }
}

인터페이스 A와 B 모두 foo()와 bar() 메소드를 선언하고 있습니다. foo() 함수는 A와 B 인터페이스 모두 구현하고 있지만 bar() 함수는 B 인터페이스에서만 구현하고 있습니다( bar() 함수가 인터페이스 A에서 추상메소드로 선언되어 있지 않은 이유는, 함수의 바디가 없다면 이것이 인터페이스의 기본 형태이기 때문입니다). 만약 C 클래스에서 A 인터페이스를 구현한다면, bar() 메소드를 오버라이드하여 구현해야만 합니다.

하지만 만약 D 클래스에서 A와 B 인터페이스를 구현한다면 A와 B 인터페이스에 있는 모든 메소드를 구현해야만 합니다. 또한 D 클래스가 함수들을 어떻게 구현할 것인지 구체적으로 작성해야 합니다. 이 규칙은 단일 구현(single implementation)을 한 bar() 메소드와 다중 구현(multiple implementations)을 한 foo() 메소드 모두에 적용됩니다.

참고 문헌

Comments