如何实现Builder模式在科特林?如何实现Builder模式在科特林?(How to implem

2019-05-13 07:41发布

你好我在科特林世界一个新手。 我喜欢我所看到迄今为止开始想将一些我们的图书馆,我们在从Java到科特林我们的应用程序中使用。

这些库是完全的POJO与setter方法,getter和生成器类。 现在我用Google找一下是落实在科特林但没有成功建设者的最佳方式。

第二次更新:现在的问题是如何写一个生成器设计模式的一个简单的POJO在科特林一些参数? 下面的代码是我试图通过编写Java代码,然后使用Eclipse的科特林-插件转换为科特林。

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
        }
    }
}

Answer 1:

首先,在大多数情况下,你不需要使用建设者科特林因为我们有默认参数和命名参数。 这使您可以编写

class Car(val model: String? = null, val year: Int = 0)

并使用它像这样:

val car = Car(model = "X")

如果你绝对要使用的建设者,这里是你如何能做到这一点:

使得构建一个companion object是没有意义的,因为object s为单身。 相反声明它作为嵌套类(其是由在科特林默认静态)。

移动性能,构造这样的对象也可以被实例化的常规方式(使构造私有,如果它不应该)和使用辅助构造函数建设者和代表到主构造。 该代码看起来如下:

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" }



Answer 2:

因为我使用的是杰克逊库从JSON解析的对象,我需要有一个空的构造,我不能有可选字段。 此外所有字段必须是可变的。 然后,我可以用这个漂亮的语法,做同样的事情Builder模式:

val car = Car().apply{ model = "Ford"; year = 2000 }


Answer 3:

我个人从来没有见过在科特林建设者,但也许这只是我。

一个需要所有验证发生在init块:

class Car(val model: String,
          val year: Int = 2000) {

    init {
        if(year < 1900) throw Exception("...")
    }
}

在这里,我花了冒昧地猜测,你没有真正想要modelyear是多变的。 还有那些默认值似乎已经没有任何意义,(特别是nullname ),但我离开一个用于演示目的。

一种观点:在Java中使用的平均生活没有命名参数Builder模式。 在一个名为参数(如科特林或Python)的语言是一种很好的做法,用的(也许可选)参数长列表构造。



Answer 4:

我已经看到,宣布额外的玩意儿作为建设者的例子很多。 我个人比较喜欢这种方式。 省力写建设者。

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))
        }

    }
}

我还没有找到一种方法,可以迫使一些领域的DSL像显示错误,而不是抛出异常进行初始化。 让我知道,如果有人知道。



Answer 5:

一种方法是做类似如下:

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()


Answer 6:

对于一个简单的类,你并不需要一个单独的建设者。 您可以按照基里尔Rakhman描述使用可选的构造函数的参数。

如果你有更复杂的类,然后科特林提供了一种方法来创建的Groovy风格的建筑商/ DSL:

类型安全的建设者

下面是一个例子:

Github上实施例-生成器/汇编



Answer 7:

我想说的模式和实施保持几乎在科特林相同。 有时你可以跳过这得益于默认值,但对于更复杂的对象创建,建筑商仍然是一个有用的工具,不能省略。



Answer 8:

您可以使用科特林例如可选参数:

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)
}

然后

myFunc("a")
myFunc("a", 1)
myFunc("a", 1, 2)
myFunc("a", 1, 2, "b")


Answer 9:

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)
        }

    }

}


Answer 10:

我实现了在科特林与后续的代码基本Builder模式:

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()
        }
    }
}

最后

Java的:

new DialogMessage.Builder( context )
       .title("Title")
       .message("Message")
       .build()
       .show();

科特林:

DialogMessage.Builder( context )
       .title("Title")
       .message("")
       .build()
       .show()


Answer 11:

人们nowdays应检查科特林的类型安全的建设者 。

使用对象创建的所述路将是这个样子:

html {
    head {
        title {+"XML encoding with Kotlin"}
    }
    // ...
}

一个很好的“在动”的使用的例子是vaadin-ON-科特林框架,它利用类型安全助洗剂,以组装视图和组件 。



Answer 12:

我是工作在暴露的Java客户端(不能采取科特林语言结构的优势)所消耗的API一个科特林项目。 我们不得不添加的建设者,使他们在Java中使用,所以我创建了一个@Builder注释: https://github.com/ThinkingLogic/kotlin-builder-annotation -它基本上为龙目岛@Builder标注为科特林的替代品。



文章来源: How to implement Builder pattern in Kotlin?