【问题标题】:How to use custom setter in Kotlin class constructor body如何在 Kotlin 类构造函数主体中使用自定义设置器
【发布时间】:2017-11-19 23:58:56
【问题描述】:

我找不到更好的标题来描述如何在这个 Kotlin 类中避免代码重复(需要表达式):

class Person(email: String) {
    var email: String = email
        set(value) {
            require(value.trim().isNotEmpty(), { "The email cannot be blank" })
            field = value
        }

    init {
        require(email.trim().isNotEmpty(), { "The email cannot be blank" })
    }
}

在 java 中,我会有一个带有名称验证的 setter,然后我会从构造函数中调用它。

在 Kotlin 中这样做的惯用方式是什么?

【问题讨论】:

    标签: kotlin


    【解决方案1】:

    使用委托。 observable() 委托已经存在。

    class Person(initialEmail: String) { // No "var" any more.
        var email: String by Delegates.observable("") {
        _, _, newValue ->
            // This code is called every time the property is set.
            require(newValue.trim().isNotEmpty(), { "The email cannot be blank" })
        }
    
        init {
            // Set the property at construct time, to invoke the delegate.
            email = initialEmail
        }
    }
    

    【讨论】:

    • 看起来 Delegates.observable(...) 委托就足够了,如果 lambda 应该抛出一个错误值的异常。
    • 绝对。我更喜欢 vetoable() 而不是 require,我自己。
    • 感谢保罗的快速回复。我尝试了使用 Delegates 的建议,但我发现它仅在属性更改其值时才有效,而在实例化新对象时无效。此外,我认为从一个应该根据字段是否更改返回 true 或 false 的方法抛出异常不是“惯用的”。
    • 你说得对,我一定有调试代码让它在我测试它时工作。我需要使用初始化。但是,这并不是一个重大变化。一秒..
    • 通常,验证不会以这种方式发生。您的模式是“记录数据然后检查”;更常见的模式是“检查数据然后记录”。即:如果email为空,则不创建对象。
    【解决方案2】:

    你可以像在 java 中那样做。您只需要删除主构造函数并改为创建辅助构造函数。不过,您将不得不手动进行分配,就像在 java 中一样。所以它看起来像这样:

    class Person {
        constructor(email: String) {
            this.email = email
        }
    
        var email: String
            set(value) {
                require(value.trim().isNotEmpty(), { "The email cannot be blank" })
                field = value
            }
    }
    

    【讨论】:

      【解决方案3】:

      在构造函数之外定义成员,并从 init 块调用 setter:

      class Person(initialEmail: String) { // This is just the constructor parameter.
          var email: String = "" // This is the member declaration which calls the custom setter.
              set(value) {          // This is the custom setter.
                  require(value.trim().isNotEmpty(), { "The email cannot be blank" })
                  field = value
              }
      
          init {
              // Set the property at construct time, to invoke the custom setter.
              email = initialEmail
          }
      }
      

      【讨论】:

      • 这并不妨碍我做Person("")
      • 已修复,根据其他答案。
      【解决方案4】:

      还有另一种方法,使用伴生对象并在那里创建对象,它有点像构造函数,并以不同的方式满足您的要求。

      data class Target(
              val date: LocalDate,
              val id: Long,
              val stringId: String,
      ) {
          companion object {
              fun create(date: LocalDate, id: Long, stringId: String?,): Target{
                  val nonNullStringId= if (stringId.isNullOrEmpty()) "" else stringId
                  return Target(date, id, nonNullStringId)
              }
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-01-07
        • 1970-01-01
        • 2010-11-30
        • 1970-01-01
        • 2019-01-10
        • 2013-02-10
        • 1970-01-01
        相关资源
        最近更新 更多