Kotlin 의 Class 및 상속

2022. 4. 18. 09:59IT/안드로이드

반응형

 

 

채소 -> 콩 -> 완두, 강낭, 렌즈 콩 등등..

이런식으로 최상위 Class와 하위 Class, 또는 Sub Class로 만들수 있다. 

이러한 관계를 프로그래밍 측면에서 어떻게 표현할지 살펴보겠습니다. Vegetable을 Kotlin의 클래스로 만들면 Legume Vegetable 클래스의 하위 클래스 또는 서브클래스로 만들 수 있습니다. 즉, Vegetable 클래스의 모든 속성과 메서드가 Legume 클래스에 상속(즉, 사용 가능함)됩니다.

Legume의 서브클래스(예: Lentil, Chickpea)를 만들어 클래스 계층 구조를 유지하고 확장할 수 있습니다. 그러면 Legume Vegetable의 하위 클래스 또는 서브클래스가 될 뿐 아니라 Lentil Chickpea의 상위 클래스 또는 슈퍼클래스가 됩니다. Vegetable은 이 계층 구조의 루트 또는 *최상위(*또는 기본) 클래스입니다.

참고: 용어 요약

다음은 이 Codelab에서 사용되는 단어와 Kotlin 클래스의 컨텍스트에서 이 단어가 의미하는 내용을 요약한 것입니다.

  • 클래스 계층 구조. 클래스가 상위 요소와 하위 요소의 계층 구조로 구성된 배열입니다. 계층 구조 다이어그램은 일반적으로 상위 요소가 하위 요소 위에 표시된 상태로 그려집니다.
  • 하위 클래스 또는 서브클래스. 계층 구조에서 다른 클래스 아래에 있는 모든 클래스입니다.
  • 상위 클래스 또는 슈퍼클래스 또는 기본 클래스. 하위 클래스가 하나 이상 있는 모든 클래스입니다.
  • 루트 또는 최상위 클래스. 클래스 계층 구조의 최상위(또는 루트)에 있는 클래스입니다.
  • 상속. 하위 클래스가 상위 클래스의 모든 속성과 메서드를 포함하거나 상속받는 경우입니다. 이를 통해 코드를 공유하고 재사용할 수 있어 프로그램을 더 쉽게 파악하고 유지할 수 있습니다.

추상 주택 클래스 만들기

어떤 클래스라도 클래스 계층 구조의 기본 클래스나 다른 클래스의 상위 클래스가 될 수 있습니다.

'추상' 클래스는 완전히 구현되지 않아서 인스턴스화할 수 없는 클래스입니다. 스케치라고 생각하면 됩니다. 스케치를 통해 무언가에 관한 아이디어와 계획을 통합하지만 그 무언가를 빌드하기에는 일반적으로 정보가 충분하지 않습니다. 스케치(추상 클래스)를 사용하여 청사진(클래스)을 만들고 청사진을 통해 실제 객체 인스턴스를 빌드합니다.

일반적으로 슈퍼클래스를 만들어 좋은 점은 모든 서브클래스에 공통적인 속성과 함수를 포함한다는 것입니다. 속성값과 함수 구현을 알 수 없으면 클래스를 추상으로 만듭니다. 예를 들어 Vegetables에는 모든 채소에 공통으로 적용되는 여러 속성이 있지만 구체적이지 않은 채소의 인스턴스를 만들 수는 없습니다. 모양이나 색상 등을 모르기 때문입니다. 따라서 Vegetable은 각 채소에 관한 구체적인 세부정보의 결정을 서브클래스에 맡기는 추상 클래스입니다.

--->아하...이런말이구만. 이제 좀 이해가 된다. 대충 겉 만 만들고....

추상 클래스 선언은 abstract 키워드로 시작합니다.

fun main() {
    val squareCabin = SquareCabin(5)
    //결과값 print 확인
    println("\n Square Cabin\n=========")
    println("Capacity: ${squareCabin.capacity}")
    println("Material: ${squareCabin.buildingMaterial}")
    println("Has room? ${squareCabin.hasRoom()}")
}

abstract class Dwelling(private var residents: Int) {
    abstract val buildingMaterial: String
    abstract val capacity: Int
    
    fun hasRoom(): Boolean {
        return residents < capacity
    }    
}

class SquareCabin(residents: Int) : Dwelling(residents) {
    // Dwelling class에서의 abstract의 초기값을 아래와 같이 정의해줘야함.
    override val buildingMaterial = "Wood"
    override val capacity = 6
}

 

 

여기서, 

	println("Capacity: ${squareCabin.capacity}")
    println("Material: ${squareCabin.buildingMaterial}")
    println("Has room? ${squareCabin.hasRoom()}")

요 부분처럼 계속 squareCabin 을 앞에 붙이기 넘나 귀찮쥬?

이럴떈 with 를 씁시다.

with (instanceName) {
    // all operations to do with instanceName
}
fun main() {
    val squareCabin = SquareCabin(5)
    /*
    println("\n Square Cabin\n=========")
    println("Capacity: ${squareCabin.capacity}")
    println("Material: ${squareCabin.buildingMaterial}")
    println("Has room? ${squareCabin.hasRoom()}")
    */
    with(squareCabin) {
        println("\n Square Cabin \n=======")
        println("Capacity: ${capacity}")
        println("Material: ${buildingMaterial}")
        println("Has Room? ${hasRoom()}")
    }
}

위와 같이 수정하면,  반복해서 squareCabin을 쓰지 않아도 된다!

class SquareCabin 과 같이, class RoundHut 을 추가한다. 

class SquareCabin(residents: Int) : Dwelling(residents) {
    override val buildingMaterial = "Wood"
    override val capacity = 6
}

class RoundHut(residents: Int) : Dwelling(residents) {
    override val buildingMaterial = "Straw"
    override val capacity = 4
}

그리고 println 은 동일하게 써주고, 확인 !

fun main() {
    val squareCabin = SquareCabin(6)
    val roundHut = RoundHut(3)
    /*
    println("\n Square Cabin\n=========")
    println("Capacity: ${squareCabin.capacity}")
    println("Material: ${squareCabin.buildingMaterial}")
    println("Has room? ${squareCabin.hasRoom()}")
    */
    with(squareCabin) {
        println("\n Square Cabin \n=======")
        println("Capacity: ${capacity}")
        println("Material: ${buildingMaterial}")
        println("Has Room? ${hasRoom()}")
    }
    
    with(roundHut) {
        println("\n Round Hut \n=======")
        println("Capacity: ${capacity}")
        println("Material: ${buildingMaterial}")
        println("Has Room? ${hasRoom()}")
    }
}

그러면 이제 아래와같이 SuperClass와 2개의 SubClass가 만들어졌다.

그리고 RoundHut 아래에 RoundTower class를 추가해보자. 

class RoundTower(residents: Int) : RoundHut(residents) {
    override val buildingMaterial = "Stone"
    override val capacity = 4
}

이렇게 추가하면, 아래와 같은 에러가 뜬다.

이 오류는 RoundHut 클래스를 서브클래스로 분류하거나 상속할 수 없음을 의미한다고 한다. !

** 기본적으로 Kotlin에서 클래스는 최종 클래스이며 서브클래스로 분류할 수 없습니다. abstract 클래스나 open 키워드로 표시된 클래스에서만 상속할 수 있습니다. 따라서 상속될 수 있도록 RoundHut 클래스를 open 키워드로 표시해야 합니다.

위의 설명인 즉슨, 

RoundHut class를 open으로 해주면 된다. 

open class RoundHut(residents: Int) : Dwelling(residents) {
    override val buildingMaterial = "Straw"
    override val capacity = 4
}

그리고 main에 print를 해서 제대로 반영이 되었는지 확인해보자. (with사용 ! )

여기서 추가로, RoundTower에 층수(Floors)라는 변수를 추가해보자.

class RoundTower(residents: Int, 
                 val floors: Int = 2) : RoundHut(residents) {
    override val buildingMaterial = "Stone"
    override val capacity = 4 * floors
}

val floors: Int 까지만 쓰면 안된다 ! 초기 값이 설정되어야한다. 그래서 = 2 를 추가해 썼다. 

다시 compile 돌려보고 결과값 확인 ! 

------------> 최종 소스코드

더보기

fun main() {
    val squareCabin = SquareCabin(6)
    val roundHut = RoundHut(3)
    val roundTower = RoundTower(8)
    /*
    println("\n Square Cabin\n=========")
    println("Capacity: ${squareCabin.capacity}")
    println("Material: ${squareCabin.buildingMaterial}")
    println("Has room? ${squareCabin.hasRoom()}")
    */
    with(squareCabin) {
        println("\n Square Cabin \n=======")
        println("Capacity: ${capacity}")
        println("Material: ${buildingMaterial}")
        println("Has Room? ${hasRoom()}")
    }
    
    with(roundHut) {
        println("\n Round Hut \n=======")
        println("Capacity: ${capacity}")
        println("Material: ${buildingMaterial}")
        println("Has Room? ${hasRoom()}")
    }
    with(roundTower) {
        println("\n Round Hut \n=======")
        println("Capacity: ${capacity}")
        println("Material: ${buildingMaterial}")
        println("Has Room? ${hasRoom()}")
    }
}

abstract class Dwelling(private var residents: Int) {
    abstract val buildingMaterial: String
    abstract val capacity: Int
    
    fun hasRoom(): Boolean {
        return residents < capacity
    }
}

class SquareCabin(residents: Int) : Dwelling(residents) {
    override val buildingMaterial = "Wood"
    override val capacity = 6
}

open class RoundHut(residents: Int) : Dwelling(residents) {
    override val buildingMaterial = "Straw"
    override val capacity = 4
}

class RoundTower(residents: Int, 
                 val floors: Int = 2) : RoundHut(residents) {
    override val buildingMaterial = "Stone"
    override val capacity = 4 * floors
}

 

728x90
반응형

'IT > 안드로이드' 카테고리의 다른 글

Kotlin의 클래스 및 상속 - 3  (1) 2022.04.18
Kotlin의 클래스 및 상속 - 2  (1) 2022.04.18
Android - Kotlin Logging & Debugging  (3) 2022.04.15
Android - Navigating  (6) 2022.04.14
Developing Android Apps with Kotlin - Layout 완성!  (10) 2022.04.12