4.1.4 내부 클래스와 중첩된 클래스
1. 클래스 A 안에 정의된 클래스 A는 중첩 클래스
- 내부 클래스 선언을 위해서는 inner 키워드 사용
class Outer {
private val bar: Int = 1
class Nested {
fun foo() = 3
}
inner class Inner() {
fun foo() = bar
}
}
val demo = Outer.Nested().foo()
val demo2 = Outer().Inner().foo()
2. Nested 클래스는 Outer 클래스의 내부 클래스가 아니므로 프로퍼티에 접근 불가능
class Outer {
private val bar: Int = 1
class Nested {
fun foo() = bar // ERROR
}
inner class Inner() {
fun foo() = bar
}
}
3. 내부 클래스에서 this@outer를 사용하여 Outer 클래스 참조할 수도 있음
class Outer {
private val bar: Int = 1
class Nested {
fun foo() = 3
}
inner class Inner() {
fun foo() = this@Outer.bar
}
}
4.1.5 봉인된 클래스
1. 상위 클래스를 상속한 하위 클래스 정의 제한
2. sealed 클래스의 하위 클래스를 정의할 때는 반드시 상위 클래스 안에 중첩시킬 것
3. when식이 모든 하위 클래스를 검사하므로 else 분기가 필요없음
sealed class Expr {
class Num(val value: Int) : Expr()
class Sum(val left: Expr, val right: Expr) : Expr()
}
fun eval(e: Expr): Int = when (e) {
is Expr.Num -> e.value
is Expr.Sum -> eval(e.left) + eval(e.right)
}
4.2.3 인터페이스에 선언된 프로퍼티 구현
interface User {
val nickname: String
}
// 주 생성자에 있는 프로퍼티
class PrivateUser(override val nickname: String): User
// 커스텀 게터
class SubscribingUser(val email: String) : User {
override val nickname: String
get() = email.substringBefore("@")
}
// 프로퍼티 초기화 식
class FacebookUser(val accountId: Int) : User {
override val nickname = getFacebookName(accountId)
}
4.2.4 게터와 세터에서 뒷받침하는 필드에 접근
1. 값을 변경하거나 읽을 때마다 정해진 로직을 실행하는 프로퍼티 구현
2. field라는 식별자를 통해 뒷받침하는 필드에 접근 가능
class User(val name: String) {
var address: String = "unspecified"
set(value :String) {
println("""
Address was changed for $name:
"$field" -> "$value"
""".trimIndent())
field = value
}
}
fun main(args: Array<String>) {
val user = User("Alice")
user.address = "KotlinApt, 123"
}
4.2.5 접근자의 가시성 변경
1. get 이나 set 앞에 가시성 변경자를 추가하여 접근자의 가시성을 변경할 수 있음
2. public으로 외부에 공개되는 프로퍼티를 외부에는 변경할 수 없도록 세터의 가시성을 private로 지정
class LengthCounter {
var counter: Int = 0
private set
fun addWord(word: String) {
counter += word.length
}
}
fun main(args: Array<String>) {
val lengthCounter = LengthCounter()
lengthCounter.addWord("Hi")
println(lengthCounter.counter)
}
4.3.3 클래스 위임: by 키워드 사용
1. 상속을 허용하지 않는 클래스에 새로운 동작 추가시 데코레이터 패턴 사용
2. 상속을 허용하지 않는 클래스 대신 사용할 수 있는 새로운 클래스(테코레이터)를 생성하여,
기존 클래스와 같은 인터페이스를 데코레이터가 제공하도록 함
3. 새로 정의해야 하는 기능은 데코레이터의 메서드에 새로 정의
4. 기존 클래스의 기능이 필요한 경우에는 데코레이터의 메서드가 기존 클래스의 메서드에게 요청을 전달
interface Base {
fun message()
fun close()
}
class A: Base {
override fun message() = println("message: A")
override fun close() = println("close: A")
}
class B(example: Base): Base by example {
override fun close() = println("close: B")
}
fun main(args: Array<String>) {
val a = A()
val b = B(a)
b.message() // message에 대한 구현을 다른 객체(a)에 위임
b.close()
}
'Android > Kotlin' 카테고리의 다른 글
[코틀린 인 액션] 6장 정리: null 다루는 방법 (0) | 2022.11.30 |
---|---|
[코틀린 인 액션] 5장 정리 (0) | 2022.11.30 |
[코틀린 인 액션] 3장 정리 (0) | 2022.11.28 |
[코틀린 인 액션] 2장 정리 (0) | 2022.11.24 |
[Kotlin] enum, sealed class (0) | 2022.09.27 |