프로그래밍 언어/코틀린

코틀린 16. 추상화

닉네임못짓는사람 2020. 12. 26. 19:31
반응형

이번 글에서는 추상화에 대해서 알아보도록 하겠습니다.

추상화


저희는 지금까지 클래스라는 게 무엇인지, 그리고 클래스를 중심으로 한 여러 가지 개념에 대해 알아보았습니다.

추상화는 이 중에서 상속과 overriding에 관련된 개념이라고 할 수 있는데, 어떤 것일지 알아봅시다.

 

저번 글에서 알아본 overriding은 슈퍼클래스에 구현된 함수를 서브클래스에서 '재정의'한다는 개념이었습니다.

하지만 추상화는 슈퍼클래스에서는 함수의 선언만 한 뒤 구체적인 내용은 구현하지 않습니다.

 

다만, 해당 함수가 슈퍼클래스를 상속하는 모든 서브클래스에 필수적으로 존재해야 한다는 부분만 명시하고,

서브클래스 내에서 어떤 동작을 하는지에 따라 맞춰서 구현하도록 되어있습니다.

이러한 함수들을 '추상함수'라고 부르며, 추상함수를 하나라도 포함한 클래스를 '추상클래스'라고 부릅니다.

 

코드를 통해서 추상함수와 추상클래스를 직접 구현해봅시다.

fun main() {
    var d1 = Cola()
    var d2 = Coffee()
    d1.drink()
    d2.drink()
}

abstract class Beberage(){
    abstract fun drink()
}

class Cola(): Beberage(){
   	override fun drink(){
        println("콜라를 마십니다.")
    }
}

class Coffee(): Beberage(){
   	override fun drink(){
        println("커피를 마십니다.")
    }
}

일단, 추상클래스를 선언하는 방법은 class앞에 abstract라는 키워드를 사용하는 것입니다.

또한 추상함수를 선언할 때에도 fun앞에 abstract를 붙여주시면 됩니다.

 

이렇게 선언된 추상함수는 선언만 한 뒤, 중괄호를 생략하고 내부를 구현하지 않습니다.

이 클래스를 Cola클래스와 Coffee클래스에서 상속받고, 함수를 overriding 해볼 텐데요.

추상클래스와 추상함수의 경우 상속과 overrding을 위해 open키워드를 적어주시지 않아도 됩니다.

 

위의 코드에서는 비어있는 drink함수를 각각 Cola클래스와 Coffee클래스에서 자신에게 맞게 정의한 것을 볼 수 있습니다.

주의해야 할 점은 이렇게 만들어진 추상클래스는 미완성된 추상함수를 가지고 있기 때문에 객체 생성이 불가능합니다.

위의 코드에서 Beberage클래스의 인스턴스를 생성하려고 하면 오류가 발생하는 것을 확인할 수 있을 겁니다.

인터페이스(interface)


이런 추상화 개념에 이어서 이번에는 인터페이스에 대해서 알아보도록 합시다.

 

코틀린에서 인터페이스는 다른 언어와 다르게 추상함수만으로 구성된 것이 아닌, 일반함수도 포함하고 있습니다.

따라서 추상클래스와 인터페이스는 몇 가지 차이점을 제외하면 비슷하다고 볼 수 있습니다.

 

먼저, 추상클래스가 생성자를 가질 수 있는 반면, 인터페이스는 생성자를 가질 수 없습니다.

따라서 서브클래스에서 상속을 받을 때, 슈퍼클래스의 생성자를 호출하는 부분이 없습니다.

 

두 번째로 인터페이스 내의 함수를 서브클래스에서 overriding해야 할 때, 슈퍼클래스에서 별도의 키워드가 필요 없습니다.

인터페이스의 경우 구현부가 있는 일반함수는 open함수로, 구현부가 없는 추상함수는 abstract함수로 인식합니다.

 

마지막으로 인터페이스는 하나의 서브클래스에서 여러 개의 인터페이스를 상속받을 수 있다는 점인데요.

여러 인터페이스를 합쳐서 하나의 서브클래스를 만들 수 있기 때문에, 클래스 설계에 큰 도움이 됩니다.

 

코드를 통해서 인터페이스를 직접 사용해보도록 합시다.

fun main() {
    var build = Building()
    var apart = Apartment()
    
    build.upStairs()
    build.upElevator()
    apart.upStairs()
    apart.upElevator()
}

interface Stairs{
    fun upStairs()
}

interface Elevator{
    fun upElevator()
}

class Building(): Stairs, Elevator{
    override fun upStairs(){
        println("계단으로 올라갑니다.")
    }
    override fun upElevator(){
        println("이 건물에는 엘리베이터가 없습니다.")
    }
}

class Apartment(): Stairs, Elevator{
    override fun upStairs(){
        println("이 건물은 계단이 막혀있습니다.")
    }
    override fun upElevator(){
        println("엘리베이터로 올라갑니다.")
    }
}

위의 코드에서는 Stairs라는 계단 클래스와, Elevator라는 엘리베이터 인터페이스를 각각 정의한 뒤,

이를 통해 건물을 올라가는 upStairs함수와 upElevator함수를 각각 정의했습니다.

 

그리고 이 둘을 상속받는 Building클래스와 Apartment클래스를 각각 정의했는데요.

두 클래스는 같은 클래스를 상속받고 같은 함수를 overriding했는데, 그 내용은 서로 다른 것을 볼 수 있습니다.

 

이렇게 추상화의 개념과 추상클래스, 그리고 인터페이스까지 알아보았습니다.

이번 글은 이 정도로 마치도록 하겠습니다.

감사합니다.

반응형

'프로그래밍 언어 > 코틀린' 카테고리의 다른 글

코틀린 18. 프로젝트 구조  (0) 2020.12.27
코틀린 17. const와 상수  (0) 2020.12.26
코틀린 15. 오버라이딩과 오버로딩  (0) 2020.12.26
코트린 14. 상속  (0) 2020.12.25
코틀린 13. 생성자  (0) 2020.12.24