코틀린은 상속이나 자바의 Decorator 와 같은 디자인 패턴을 사용하지 않은 채 클래스를 확장
할 수 있습니다. 확장(Extensions)
란 기존 클래스에 프로퍼티나 함수를 추가하는 것을 의미합니다.
third-party library 와 같이 수정이 불가했던 라이브러리 들도 확장
가능합니다.
이렇게 추가한 함수를 extension functions
, 추가한 프로퍼티를 extension properties
라고 부릅니다.
extension function 을 선언하기 위해서는 함수의 이름 앞에 receiver type(확장하고자 하는 클래스의 타입
을 붙여주어야 합니다.
예를 들어, MutableList<Int>
에 swap
함수를 확장해 보겠습니다.
fun main() {
val list = mutableListOf(0,1,2)
list.swap(1,2)
}
fun MutableList<Int>.swap(index1: Int, index2: Int) {
val temp = this[index1]
this[index1] = this[index2]
this[index2] = temp
}
MutableList<Int>
클래스에는 swap
라는 메소드가 없지만, 확장을 통해 있는 메소드처럼 사용하였습니다.
MutableList<Int>
를 receiver type
이라고 합니다.swap
은 확장 함수의 이름입니다.this
를 receiver object
라고 하며, receiver class
가 원래 가지고 있는 메소드를 호출해서 사용할 수 있습니다.extension
은 실제로 클래스 자체를 수정하는 것이 아니라 .
표기로 호출되는 함수를 만들어 내부적으로 추가된 것 처럼 사용할 수 있게 하는 것입니다.
extension
은 해당 함수를 호출하는 객체의 클래스 타입에 맞춰 실행됩니다.
open class Shape
class Rectangle: Shape()
fun Shape.getName() = "Shape"
fun Rectangle.getName() = "Rectangle"
fun printClassName(s: Shape){
println(s.getName())
}
fun main(){
printClassName(Rectangle())
}
👉 Shape
위 예제의 결과로 Shape 이 나온 것을 통해 확인 할 수 있습니다. 파라미터의 타입이 Shape 으로 선언되었기 때문에 인스턴스가 Rectangle 일 지라도 Shape.getName 이 호출됩니다.
클래스의 멤버 함수와 확장 함수의 이름, 파라미터가 같은 경우, 항상 원래 클래스의 멤버 함수를 호출합니다. 아래의 예제를 통해 확인할 수 있습니다.
class Example{
fun printFunctionType() {
println("class Method")
}
}
fun Example.printFunctionType() {
println("Extension function")
}
fun main(){
Example().printFunctionType()
}
👉 class Method
그러나, 확장 함수가 기존 클래스의 멤버 함수와 이름이 같지만 파라미터가 다른 함수를 overloading 하는 것은 가능합니다.
class Example{
fun printFunctionType() {
println("class Method")
}
}
fun Example.printFunctionType(i: Int) {
println("Extension function")
}
fun main(){
Example().printFunctionType(1)
}
👉 Extension function
companion object 도 확장
할 수 있다.
class MyClass {
companion object { } // will be called "Companion"
}
fun MyClass.Companion.printCompanion() { println("companion") }
fun main() {
MyClass.printCompanion()
}
extension function 은 주로 top-level( 패키지 바로 아래) 선언된다.