Key*_*han 121 design-patterns kotlin
嗨,我是Kotlin世界的新手.我喜欢到目前为止所看到的并开始考虑将我们在Java应用程序中使用的一些库转换为Kotlin.
这些库充满了带有setter,getter和Builder类的Pojos.现在我用谷歌搜索了什么是在Kotlin中实施Builders的最佳方法,但没有成功.
第二次更新:问题是如何在Kotlin中使用一些参数为简单的pojo编写Builder设计模式?下面的代码是我尝试编写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
}
}
}
Run Code Online (Sandbox Code Playgroud)
Kir*_*man 235
首先,在大多数情况下,您不需要在Kotlin中使用构建器,因为我们有默认和命名参数.这使您可以写
class Car(val model: String? = null, val year: Int = 0)
Run Code Online (Sandbox Code Playgroud)
并像这样使用它:
val car = Car(model = "X")
Run Code Online (Sandbox Code Playgroud)
如果你绝对想要使用构建器,那么你可以这样做:
使构建器成为一个companion object没有意义,因为objects是单例.而是将其声明为嵌套类(默认情况下在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)
}
}
Run Code Online (Sandbox Code Playgroud)
用法: 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)
}
}
Run Code Online (Sandbox Code Playgroud)
用法: 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)
}
}
Run Code Online (Sandbox Code Playgroud)
用法: val car = Car.build(required = "requiredValue") { model = "X" }
Dav*_*vra 10
因为我使用Jackson库来解析JSON中的对象,所以我需要一个空构造函数,而且我不能有可选字段.所有字段都必须是可变的.然后我可以使用这个与Builder模式相同的漂亮语法:
val car = Car().apply{ model = "Ford"; year = 2000 }
Run Code Online (Sandbox Code Playgroud)
小智 8
一种方法是执行以下操作:
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)
}
}
Run Code Online (Sandbox Code Playgroud)
用法样本:
val car = Car.Builder()
.model("Ford Focus")
.color("Black")
.type("Type")
.build()
Run Code Online (Sandbox Code Playgroud)
我个人从未见过Kotlin的建筑师,但也许只是我.
所有验证都需要在init块中发生:
class Car(val model: String,
val year: Int = 2000) {
init {
if(year < 1900) throw Exception("...")
}
}
Run Code Online (Sandbox Code Playgroud)
在这里,我冒昧地猜测你并不是真的想要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))
}
}
}
Run Code Online (Sandbox Code Playgroud)
我还没有找到一种方法可以强制在 DSL 中初始化某些字段,例如显示错误而不是抛出异常。如果有人知道,请告诉我。