안녕하세요 저는 Kotlin 세계의 초보자입니다. 나는 지금까지 본 것을 좋아하고 응용 프로그램에서 사용하는 일부 라이브러리를 Java에서 Kotlin으로 변환하려고 생각하기 시작했습니다.
이 라이브러리는 setter, getter 및 Builder 클래스가있는 Pojo로 가득합니다. 이제 Kotlin에서 빌더를 구현하는 가장 좋은 방법은 무엇인지 알아 보았지만 성공하지 못했습니다.
두 번째 업데이트 : 문제는 Kotlin에서 일부 매개 변수를 사용하여 간단한 pojo에 대한 빌더 디자인 패턴을 작성하는 방법입니다. 아래 코드는 Java 코드를 작성한 다음 eclipse-kotlin-plugin을 사용하여 Kotlin으로 변환하여 시도한 것입니다.
class Car private constructor(builder:Car.Builder) {
var model:String? = null
var year:Int = 0
init {
this.model = builder.model
this.year = builder.year
}
companion object Builder {
var model:String? = null
private set
var year:Int = 0
private set
fun model(model:String):Builder {
this.model = model
return this
}
fun year(year:Int):Builder {
this.year = year
return this
}
fun build():Car {
val car = Car(this)
return car
}
}
}
답변
무엇보다도 기본적으로 명명 된 인수가 있기 때문에 대부분의 경우 Kotlin에서 빌더를 사용할 필요가 없습니다. 이것은 당신이 쓸 수 있습니다
class Car(val model: String? = null, val year: Int = 0)
다음과 같이 사용하십시오.
val car = Car(model = "X")
빌더를 절대적으로 사용하려면 다음과 같이하십시오.
S는 싱글 톤 companion object
이기 때문에 Builder를 만드는 것은 의미가 없습니다 object
. 대신 중첩 클래스로 선언하십시오 (Kotlin에서는 기본적으로 정적입니다).
객체를 규칙적으로 인스턴스화 할 수 있도록 속성을 생성자로 이동하고 (생성하지 않아야하는 경우 생성자를 비공개로 설정) 빌더를 사용하여 기본 생성자로 위임하는 보조 생성자를 사용하십시오. 코드는 다음과 같습니다.
class Car( //add private constructor if necessary
val model: String?,
val year: Int
) {
private constructor(builder: Builder) : this(builder.model, builder.year)
class Builder {
var model: String? = null
private set
var year: Int = 0
private set
fun model(model: String) = apply { this.model = model }
fun year(year: Int) = apply { this.year = year }
fun build() = Car(this)
}
}
용법: val car = Car.Builder().model("X").build()
빌더 DSL 을 사용하여이 코드를 추가로 단축 할 수 있습니다 .
class Car (
val model: String?,
val year: Int
) {
private constructor(builder: Builder) : this(builder.model, builder.year)
companion object {
inline fun build(block: Builder.() -> Unit) = Builder().apply(block).build()
}
class Builder {
var model: String? = null
var year: Int = 0
fun build() = Car(this)
}
}
용법: val car = Car.build { model = "X" }
일부 값이 필요하고 기본값이없는 경우 빌더의 생성자 및 build
방금 정의한 메소드에 값을 입력해야합니다 .
class Car (
val model: String?,
val year: Int,
val required: String
) {
private constructor(builder: Builder) : this(builder.model, builder.year, builder.required)
companion object {
inline fun build(required: String, block: Builder.() -> Unit) = Builder(required).apply(block).build()
}
class Builder(
val required: String
) {
var model: String? = null
var year: Int = 0
fun build() = Car(this)
}
}
용법: val car = Car.build(required = "requiredValue") { model = "X" }
답변
한 가지 방법은 다음과 같은 작업을 수행하는 것입니다.
class Car(
val model: String?,
val color: String?,
val type: String?) {
data class Builder(
var model: String? = null,
var color: String? = null,
var type: String? = null) {
fun model(model: String) = apply { this.model = model }
fun color(color: String) = apply { this.color = color }
fun type(type: String) = apply { this.type = type }
fun build() = Car(model, color, type)
}
}
사용 샘플 :
val car = Car.Builder()
.model("Ford Focus")
.color("Black")
.type("Type")
.build()
답변
JSON에서 객체를 구문 분석하기 위해 Jackson 라이브러리를 사용하고 있기 때문에 빈 생성자가 필요하며 선택적 필드를 가질 수 없습니다. 또한 모든 필드는 변경 가능해야합니다. 그런 다음 빌더 패턴과 동일한 기능을하는이 멋진 구문을 사용할 수 있습니다.
val car = Car().apply{ model = "Ford"; year = 2000 }
답변
나는 개인적으로 Kotlin에서 건축업자를 본 적이 없지만 아마도 나일 것입니다.
init
블록 에서 필요한 모든 유효성 검사가 발생합니다 .
class Car(val model: String,
val year: Int = 2000) {
init {
if(year < 1900) throw Exception("...")
}
}
여기 당신이 정말로 원하는하지 않는 것이 생각하는 자유를했다 model
및 year
변경 될 수 있습니다. 또한 그 디폴트 값은 아무 의미가없는 것 같다 (특히 null
대한 name
)하지만 난 데모 용으로 하나 떠났다.
의견 :
명명 된 매개 변수없이 살기위한 수단으로 Java에서 사용되는 빌더 패턴. Kotlin 또는 Python과 같은 명명 된 매개 변수가있는 언어에서는 매개 변수가 긴 (선택적) 매개 변수 목록이있는 생성자를 사용하는 것이 좋습니다.
답변
추가 재미를 빌더로 선언하는 많은 예제를 보았습니다. 나는 개인적으로이 접근법을 좋아한다. 빌더를 작성하는 노력을 절약하십시오.
package android.zeroarst.lab.koltinlab
import kotlin.properties.Delegates
class Lab {
companion object {
@JvmStatic fun main(args: Array<String>) {
val roy = Person {
name = "Roy"
age = 33
height = 173
single = true
car {
brand = "Tesla"
model = "Model X"
year = 2017
}
car {
brand = "Tesla"
model = "Model S"
year = 2018
}
}
println(roy)
}
class Person() {
constructor(init: Person.() -> Unit) : this() {
this.init()
}
var name: String by Delegates.notNull()
var age: Int by Delegates.notNull()
var height: Int by Delegates.notNull()
var single: Boolean by Delegates.notNull()
val cars: MutableList<Car> by lazy { arrayListOf<Car>() }
override fun toString(): String {
return "name=$name, age=$age, " +
"height=$height, " +
"single=${when (single) {
true -> "looking for a girl friend T___T"
false -> "Happy!!"
}}\nCars: $cars"
}
}
class Car() {
var brand: String by Delegates.notNull()
var model: String by Delegates.notNull()
var year: Int by Delegates.notNull()
override fun toString(): String {
return "(brand=$brand, model=$model, year=$year)"
}
}
fun Person.car(init: Car.() -> Unit): Unit {
cars.add(Car().apply(init))
}
}
}
아직 예외를 throw하는 대신 오류를 표시하는 것처럼 일부 필드를 DSL에서 초기화 할 수있는 방법을 아직 찾지 못했습니다. 아는 사람이 있으면 알려주세요.
답변
간단한 수업의 경우 별도의 빌더가 필요하지 않습니다. Kirill Rakhman이 설명한대로 선택적 생성자 인수를 사용할 수 있습니다.
더 복잡한 수업이있는 경우 Kotlin은 Groovy 스타일 빌더 / DSL을 작성하는 방법을 제공합니다.
예를 들면 다음과 같습니다.
답변
요즘 사람들은 Kotlin의 Type-Safe Builders를 확인해야합니다 .
위에서 언급 한 객체 생성 방식은 다음과 같습니다.
html {
head {
title {+"XML encoding with Kotlin"}
}
// ...
}
유용한 ‘실제’사용 예는 유형 안전 빌더를 사용하여 뷰와 컴포넌트 를 조립 하는 vaadin-on-kotlin 프레임 워크 입니다.