【问题标题】:Fluent methods for data class in kotlinkotlin 中数据类的流利方法
【发布时间】:2017-05-21 14:41:13
【问题描述】:

我们熟悉在 java 和其他编程语言中调用方法的流畅接口。例如:

Picasso.with(this).load(url).into(imageView);

这可以通过 setter 方法返回所需类型的对象来实现。

public Picasso with(Context context)
{
    this.context = context;
    return this;
}

public X load(String url)
{
    this.url = url;
    return this;
}

public Y load(ImageView imageView)
{
    this.imageView = imageView;
    return this;
}

我正在尝试对 kotlin 数据类做同样的事情但遗憾的是我找不到一种方法来覆盖我可以返回该对象的新实例的 setter 方法。

当我尝试强制覆盖 setter 方法时出现编译器错误。

任何关于可以做什么的想法,以便我可以调用流畅的接口或至少改变 setter 的工作方式 可能是这样的

data class CorruptOfficeAccount(.....){
     override fun addCollectedFee(Long money) :CorruptOfficeAccount {
     this.money = money/5
    }
}

这样我就可以打电话了

CorrutOfficeAccount(....).method1().addCollectedFee(20000).method3()

【问题讨论】:

  • 考虑接受另一个更好的答案。

标签: java kotlin fluent-interface


【解决方案1】:

如果除了Name 不需要返回任何东西,你可以这样做:

data class Name(var firstName: String, var lastName: String)

fun foo() {
    val name = ...
    name.apply {
        firstName = ...
        lastName = ...
    }
}

或另一个例子:

CorrutOfficeAccount(....).apply {
    method1()
    addCollectedFee(20000)
    method3()
}

在传递给apply 的函数内部(大括号内的内容),this 是对象apply 被调用,这使得无需编写@ 即可引用firstName 等成员函数和属性987654328@.

如果您对此不满意:不可能让实际的 setter 返回一些东西,但是您当然可以定义一个具有不同名称的方法并让它返回一些东西。

【讨论】:

  • 第一个示例并没有真正起作用,因为您无法在没有所有属性的情况下构造Name,然后再次设置它们。他们需要具有该示例的默认值才能正常工作。
  • 这不会编译
【解决方案2】:

在 Kotlin 中访问属性时,我们不使用 getter 和 setter 函数,虽然您可以覆盖它们的 setter 以赋予它们自定义行为,但不能让它们返回任何内容,因为调用它们是一个赋值,即不是 Kotlin 中的表达式。例如,这不起作用:

var x = 1
var y = (x = 5) // "Assigments are not expressions, and only expressions are allowed in this context"

您可以做的是定义设置它们的其他方法,然后返回调用它们的实例。例如:

data class Name(var firstName: String = "", var lastName: String  =  "") {
    fun withLastName(lastName: String): Name {
        this.lastName = lastName
        return this
    }
}

val name = Name(firstName = "Jane") 
name.withLastName("Doe").withLastName("Carter")

请注意,如果将此方法命名为setLastName,则在使用Java 类时会遇到问题,因为在编写Java 代码时,lastName 属性已经通过名为setLastName 的方法可见。

不过,Kotlin 中可能更常见的解决方案是使用标准库中的 apply 替换 fluent 构建器,正如 Christian 的回答中已经描述的那样。

【讨论】:

  • 您应该编辑此示例以提供名字/姓氏的默认值,否则必须使用它们构建类,然后立即更改它们的值是没有意义的。
【解决方案3】:

感谢 Zsmb13 和 Christin 的回答,但如果有人想使用不可变字段,我还有另一个解决方案

data class Foo(val fooString: String = "", val fooInt: Int = 0) {
    fun increaseTwo() = copy(fooInt = fooInt + 2)
    fun increaseThree() = copy(fooInt = fooInt + 3)
}

你可以这样使用它

println( Foo("foo",2).increaseTwo().increaseThree())

输出:

Foo(fooString=foo, fooInt=7)

【讨论】:

    猜你喜欢
    • 2016-09-28
    • 1970-01-01
    • 2014-07-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-13
    • 1970-01-01
    相关资源
    最近更新 更多