Skip to content

DSL

영역 특화 언어(Domain Specific Language)를 사용해 코틀린다운 API를 설계하는 방법에 대해 소개한다.

전통적인 API와 DSL 형식의 API의 차이를 설명하고 DSL 형식의 API로 DB 접근, HTML 생성, 테스트, 빌드 등 사용법도 소개한다.

그리고 invoke 관례를 사용해 DSL 코드 내에 람다와 프로퍼티 대입을 더 유연하게 조립할 수 있다.

API에서 DSL로

DSL의 궁극적 목표는 코드의 가독성와 유지 보수성을 좋게 유지하는 것이다. 클래스에 있는 코드들은 대부분 다른 클래스와 상호작용을 한다. 따라서 그런 상호작용을 하는 지점인 인터페이스를 잘 살펴봐야한다. 한마디로 클래스의 API를 살펴봐야한다.

코틀린에서 간결한 구문을 위해 지원하는 기능에 대해 표로 살펴보자.

일반구문간결한 구문언어 특성
StringUtil.capitalize(s)s.capitalize()확장 함수
1.to("one")1 to "one"중위 호출
set.add(2)set += 2연산자 오버로딩
map.get("key")map["key"]get 메소드에 대한 관례
file.use({f -> f.read()})file.use { it.read() }람다를 괄호 밖으로 빼내는 관례
sb.append("yes"); sb.append("no")with (sb) { append("yes"); append("no"); }수신 객체 지정 람다

더 나아가 DSL 구축을 도와주는 코틀린 기능을 살펴본다.

invoke 관례를 사용한 유연한 블록 중첩

관례는 특별한 이름이 붙은 함수를 일반 메소드에 호출 구문으로 호출하지 않고 더 간단한 다른 구문으로 호출할 수 있게 지원하는 기능이다.

예를 들어 get 관례에 대해서 foo[bar]foo.get(bar)로 변환된다. invoke도 이와 같은 역할을 한다.

다만 invoke는 get과 달리 각괄호 대신 소괄호를 사용한다. operator 변경자가 붙은 invoke 메소드 정의가 들어있는 클래스의 객체를 함수처럼 호출할 수 있다.

kotlin

class Greeter(val greeting: String) {
    operator fun invoke(name: String) {
        println("$greeting, $name!")
    }
}

>> val greeter = Greeter("Hello")
>> greeter("Echo")

Hello, Echo!

invoke 메서드는 파라미터 타입 개수에 제한도 없다. 메서드 오버로딩도 할 수 있다.

Email: echo.youn@kakao.com