<다형성 Polymorphysm>
다형성의 개념을 음료에 비교해 표현하자면 우리가 목이 말라서 아무 음료나 마셔도 좋을 때도 있지만
각자 기호에 맞춰 물, 콜라 혹은 사이다를 마시고 싶을 때가 있습니다
이때 콜라를 '콜라 자체'로도 볼 수 있지만 '음료라는 특성'으로도 볼 수 있도록 만드는 것이
'다형성'의 개념입니다
이를 코틀린 코드로 살펴보자면
음료라는 클래스(Drink)와 이를 상속받은 콜라라는 클래스(Cola)가 있습니다
이때 콜라의 인스턴스를 만들 때는 상속관계에 있는 수퍼클래스인 음료를 담는 공간에
콜라를 담는 공간이 추가되어 추가됩니다
이렇게 만들어진 콜라의 인스턴스는 음료를 담는 변수에 저장하면 음료의 기능만 사용하게 되고
( var a: Drink = Cola() )
콜라를 담는 변수에 저장하면 콜라의 기능까지 모두 사용할 수 있습니다
( var b: Cola = Cola() )
이때 콜라 인스턴스를 음료 변수에 담는 행위를 상위 자료형인 수퍼클래스로 변환한다고 하여
Up-Casting (업캐스팅)이라고 하고, 업캐스팅된 인스턴스를 다시 하위 자료형으로 변환하면
Down-Casting (다운캐스팅)이라고 부릅니다
그런데 업캐스팅은 그냥 상위 자료형에 담는 것으로 ( var a: Drink = Cola() ) 동작하지만
다운캐스팅은 '별도의 연산자'가 필요합니다
바로 as와 is 연산자 입니다
'as'는 변수를 호환되는 자료형으로 변환해주는 캐스팅 연산자로 코드 내에서 사용할 시 즉시 자료형을 변환해주며
변환된 자료형을 반환도 해주는 연산자입니다
var a : Drink = Cola()
a as Cola // 이후 a는 Cola로 동작함
var b = a as Cola // Cola로 변환한 결과를 반환받아 변수에 넣을 수 있음
'is'는 변수가 자료형에 호환되는지를 먼저 '체크한 후 변환'해주는 캐스팅 연산자로 조건문 내에서 사용되는 특징이 있습니다
var a: Drink = Cola()
if (a is Cola) {
// 이 안에서만 a가 Cola가 됨
}
위의 내용들을 코드 예시로 확인해보도록 하겠습니다
fun main() {
var a = Drink()
a.drink()
var b: Drink = Cola()
b.drink()
if (b is Cola) {
b.washDishes()
}
var c = b as Cola
c.washDishes()
b.washDishes()
}
open class Drink {
var name = "음료"
open fun drink() {
println("${name}를 마십니다")
}
}
class Cola: Drink() { // Drink 클래스 상속
var type = "콜라"
override fun drink() {
println("${name} 중에 ${type}을 마십니다")
}
fun washDishes() {
println("${type}로 설거지를 합니다")
}
}
/* 출력
음료를 마십니다
음료 중에 콜라를 마십니다
콜라로 설거지를 합니다
콜라로 설거지를 합니다
콜라로 설거지를 합니다
*/
상속이 가능하도록 하기 위해 Drink클래스는 open class로 만들어 주었습니다
속성으로 name이라는 변수에 음료라는 문자열을 할당해주고
drink라는 함수 또한 override가 가능하도록 open 함수로 만들었습니다
다음으로 Drink 클래스를 상속받아 Cola 클래스를 만들었습니다
type이라는 변수를 만들어 콜라라는 문자열을 할당하고
drink 함수를 override하여 새로 만들어주었습니다
또한 washDishes 함수도 추가해주었습니다
이제 main에서는 Drink의 인스턴스를 만들어 a에 담고 a의 drink라는 함수를 호출해주었습니다
실행해보면 Drink의 인스턴스에 있는 drink 함수를 호출했기 때문에 "음료를 마십니다"가 출력되는 것을 확인할 수 있습니다
다음으로 Cola의 인스턴스를 만들어 Drink 타입의 변수 b에 할당하고 b의 drink 함수를 호출하였습니다
실행해보면 b는 Drink 타입의 변수이지만 Cola의 인스턴스를 담았으므로
Cola에서 override 한 함수가 실행되는 것을 확인할 수 있습니다
하지만 b는 Drink 변수이므로 그 상태에선 washDishes 함수를 호출할 수는 없습니다!
이때는 is 혹은 as를 통해 다운캐스팅을 해야합니다
if문을 추가하여 b is Cola 라는 구문으로 b가 Cola와 호환되는지 여부를 확인하고
중괄호 안에서 b의 washDishes 함수를 호출하면 "콜라로 설거지를 합니다" 가 출력되는 것을 확인할 수 있습니다
*is는 조건문 안에서만 잠시 다운캐스팅 됩니다!!
다음으론 b as Cola로 다운캐스팅 한 것을 변수 c에 할당해보았습니다
그리고 c에서 washDishes 함수를 호출하면 똑같이 출력되는 것을 확인할 수 있습니다
그런데 이때 b에서 washDishes 함수를 호출해도 똑같은 결과가 나오는데요,
이는 as를 사용하면 반환값 뿐만 아니라 변수 자체도 다운캐스팅 되기 때문입니다
다형성은 클래스의 상속관계에서 오는 인스턴스의 호환성을 활용할 수 있는 기능으로
수퍼클래스가 같은 인스턴스를 한번에 관리하거나 인터페이스를 구현하여 사용하는 코드에서도 이용됩니다
<클래스의 다형성> 포스팅은 여기서 마치도록 하겠습니다
'Kotlin' 카테고리의 다른 글
[Kotlin] 제너릭 Generic (0) | 2023.08.18 |
---|---|
[Kotlin] 익명객체와 옵저버 패턴 (0) | 2023.07.28 |
[Kotlin] 오브젝트 Object (0) | 2023.07.27 |
[Kotlin] 스코프 함수 (0) | 2023.07.26 |
[Kotlin] 고차함수와 람다함수 (0) | 2023.07.25 |