Kotlin에서 빌더 패턴을 구현하는 방법은 무엇입니까?
안녕하세요 저는 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" }
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과 같은 명명 된 매개 변수가있는 언어의 경우 매개 변수가 긴 (선택적) 매개 변수 목록이있는 생성자를 사용하는 것이 좋습니다.
한 가지 방법은 다음과 같은 작업을 수행하는 것입니다.
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()
추가 재미를 빌더로 선언하는 많은 예제를 보았습니다. 나는 개인적으로이 접근법을 좋아한다. 빌더를 작성하는 노력을 절약하십시오.
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 프레임 워크 입니다.
나는 파티에 늦었다. 프로젝트에서 Builder 패턴을 사용해야한다면 같은 딜레마가 발생했습니다. 나중에, 연구 후에 Kotlin은 이미 명명 된 인수와 기본 인수를 제공하기 때문에 절대적으로 불필요하다는 것을 깨달았습니다.
If you really need to implement, Kirill Rakhman's answer is solid answer on how to implement in most effective way. Another thing you may find it useful is https://www.baeldung.com/kotlin-builder-pattern you can compare and contrast with Java and Kotlin on their implementation
I would say the pattern and implementation stays pretty much the same in Kotlin. You can sometimes skip it thanks to default values, but for more complicated object creation, builders are still a useful tool that can't be omitted.
you can use optional parameter in kotlin example:
fun myFunc(p1: String, p2: Int = -1, p3: Long = -1, p4: String = "default") {
System.out.printf("parameter %s %d %d %s\n", p1, p2, p3, p4)
}
then
myFunc("a")
myFunc("a", 1)
myFunc("a", 1, 2)
myFunc("a", 1, 2, "b")
class Foo private constructor(@DrawableRes requiredImageRes: Int, optionalTitle: String?) {
@DrawableRes
@get:DrawableRes
val requiredImageRes: Int
val optionalTitle: String?
init {
this.requiredImageRes = requiredImageRes
this.requiredImageRes = optionalTitle
}
class Builder {
@DrawableRes
private var requiredImageRes: Int = -1
private var optionalTitle: String? = null
fun requiredImageRes(@DrawableRes imageRes: Int): Builder {
this.intent = intent
return this
}
fun optionalTitle(title: String): Builder {
this.optionalTitle = title
return this
}
fun build(): Foo {
if(requiredImageRes == -1) {
throw IllegalStateException("No image res provided")
}
return Foo(this.requiredImageRes, this.optionalTitle)
}
}
}
I implemented a basic Builder pattern in Kotlin with the follow code:
data class DialogMessage(
var title: String = "",
var message: String = ""
) {
class Builder( context: Context){
private var context: Context = context
private var title: String = ""
private var message: String = ""
fun title( title : String) = apply { this.title = title }
fun message( message : String ) = apply { this.message = message }
fun build() = KeyoDialogMessage(
title,
message
)
}
private lateinit var dialog : Dialog
fun show(){
this.dialog= Dialog(context)
.
.
.
dialog.show()
}
fun hide(){
if( this.dialog != null){
this.dialog.dismiss()
}
}
}
And finally
Java:
new DialogMessage.Builder( context )
.title("Title")
.message("Message")
.build()
.show();
Kotlin:
DialogMessage.Builder( context )
.title("Title")
.message("")
.build()
.show()
I was working on a Kotlin project that exposed an API consumed by Java clients (which can't take advantage of the Kotlin language constructs). We had to add builders to make them usable in Java, so I created an @Builder annotation: https://github.com/ThinkingLogic/kotlin-builder-annotation - it's basically a replacement for the Lombok @Builder annotation for Kotlin.
참고URL : https://stackoverflow.com/questions/36140791/how-to-implement-builder-pattern-in-kotlin
'IT story' 카테고리의 다른 글
쉼표가있는 삼항 연산자가 실제 경우에 하나의 표현식 만 평가하는 이유는 무엇입니까? (0) | 2020.07.17 |
---|---|
“캐치”없이“시도 적으로”수행하는 것이 합리적입니까? (0) | 2020.07.17 |
NumPy 배열에서 0과 같은 원소의 인덱스 찾기 (0) | 2020.07.17 |
JavaScript에서 함수를 주기적으로 호출하는 방법이 있습니까? (0) | 2020.07.17 |
PHP 추상 속성 (0) | 2020.07.17 |