이펙티브 코틀린 아이템 34: 기본 생성자에 이름 있는 옵션 아규먼트를 사용하라

이펙티브 코틀린(객체생성)

아이템 34: 기본 생성자에 이름 있는 옵션 아규먼트를 사용하라

기본 생성자 : 객체를 정의하고 생성하는 방법을 지정할때 사용하는 가장 기본적인 방법

1
2
3
class User(var name: String, var surname: String)

val user = User("Zola", "Gianfranco")

점층적 생성자 패턴(telescoping constructor pattern)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

class Pizza {
val size: String
val cheese: Int
val olives: Int
val bacon: Int

constructor(size: String, cheess: Int, olives: Int, bacon: Int) {
this.size = size
this.cheess = cheess
this.olives = olives
this.bacon = bacon
}
constructor(size: String, cheese: Int, olives: Int): this(size, cheese, olives, 0)
constructor(size: String, cheese: Int): this(size, cheese, 0)
constructor(size: String): this(size, 0)
}

코틀린은 디폴트 아규먼트(default argument)를 사용할 수 있기 때문에 아래처럼 사용할수 있다.

1
2
3
4
5
6
7
8

class Pizza(
val size: String,
val cheese: Int = 0,
val olives: Int = 0,
val bacon: Int = 0
)

빌더 패턴(builder pattern)

자바에서는 네임드 파라미터(named parameter)와 디폴트 아규먼트(default argument)를 사용할 수 없다. 그래서 빌더 패턴을 사용한다.

빌더 패턴의 장점

  • 파라미터에 이름을 가진다.
  • 파라미터를 원하는 순서대로 지정
  • 디폴트 값을 지정
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Pizza private constructor(
val size: String,
val cheese: Int,
val olives: Int,
val bacon: Int
) {
class Builder(private val size: String) {
private var cheese: Int = 0
private var olives: Int = 0
private var bacon: Int = 0

fun setCheese(value: Int): Builder = apply {
cheese = value
}

// ...

fun build() = Pizza(size, cheese, olives, bacon)
}
}

코틀린은 빌더 패턴을 사용하는것 보다 네임드 파라미터를 사용하는게 좋다.

값의 의미를 묶어서 지정할때나 특정값을 누적하는 형태로 사용될때 빌더 패턴을 이용하는것이 나을수도 있는데
코틀린에서는 DSL 빌더를 이용해서 구현하는것을 더 좋게 본다(?)

빌더 패턴은 다음과 같은 경우에만 사용

  • 빌더 패턴을 사용하는 다른 언어로 작성된 라이브러리를 그대로 옮길 때
  • 디폴트 아규먼트와 DSL을 지원하지 않는 다른 언어에서 쉽게 사용할 수 있게 API를 설계할 때

참조