【问题标题】:Avoiding boilerplate for defining getters and setters in Scala避免在 Scala 中定义 getter 和 setter 的样板
【发布时间】:2014-07-20 05:48:02
【问题描述】:

我正在用 Scala 开发一个桌面应用程序,它有几十个用户可以配置的配置选项。这些选项被定义为一个特征,以便单元测试和运行时应用程序可以有单独的实现:

trait Config {
  var showNotifications: Boolean
  var showOverlay: Boolean
  // ...several dozen similar options
}

单元测试的实现很简单:

object TestConfig extends Config {
  var showNotifications: Boolean = true
  var showOverlay: Boolean = false
  // ...
}

但是,运行时使用的实现更复杂,因为它需要持久化更改并通知各种侦听器。我直接定义了getter和setter来实现这一点;每个 getter 和 setter 都引用一个标准方法,如下所示:

class UserConfig extends Config {

  class BooleanPref(val key: String, val default: Boolean) {
    def get = {
      // ... load configuration option ...
    }
    def set(value: Boolean) = {
      // ... save configuration option ...
    }
  }

  val prefShowNotifications = new BooleanPref("showNotifications", true)
  def showNotifications: Boolean = prefShowNotifications.get
  def showNotifications_=(value: Boolean) = prefShowNotifications.set(value)

  val prefShowOverlay = new BooleanPref("showOverlay", false)
  def showOverlay: Boolean = prefShowOverlay.get
  def showOverlay_=(value: Boolean) = prefShowOverlay.set(value)

  // ... repeated several dozen times ...

}

这会导致大量样板代码,这似乎是不必要的。 getter 和 setter 都必须为每个配置选项单独映射,即使它们都以完全相同的方式工作。

Scala 中是否有任何方法可以同时定义 getter 和 setter? IE。而不是这个:

val prefShowNotifications = new BooleanPref("showNotifications", true)
def showNotifications: Boolean = prefShowNotifications.get
def showNotifications_=(value: Boolean) = prefShowNotifications.set(value)

是否可以分配一个同时实现 getter 和 setter 的对象或函数,例如:

val showNotifications: Boolean = // something here

或者有没有其他方法可以避免单独定义 getter 和 setter?

【问题讨论】:

  • 我不明白为什么你需要 getter 和 setter。默认情况下,字段是公开的。
  • UserConfig 不在类中存储值,它调用 API 在外部记录值(例如,在 Windows 注册表中)。将值作为字段存储在 UserConfig 中是不合适的,因为它总是需要从外部 API 中查找最新值,因此它需要 getter 和 setter 方法。
  • 如果您只创建一个方法,然后根据您需要它执行的操作来处理多个案例类,那么这会采取相反的方法。与其让一百万个方法都调用相同的 getter 和 setter,不如使用一个 getter 和 setter 来接受一百万个不同的选项
  • @ElectricCoffee 我可以试试看是否更好......要清楚:你是否建议我创建一个新的抽象类来定义案例类,如ShowNotificationsShowOverlay 等,然后Config trait 只有一个 get 和一个 set 方法?
  • @gutch 您不需要将案例类放入抽象类中。您只需将案例类传递给 BooleanPref 取决于您需要什么样的功能

标签: scala getter-setter


【解决方案1】:

这样的事情应该会大大简化您的代码。

trait Config {
  sealed trait BooleanPref
  case object ShowNotificationPref extends BooleanPref
  ...

  def set(pref: BooleanPref, value: Boolean): Unit
  def get(pref: BooleanPref): Boolean
}

class UserConfig extends Config {          
  def get(pref: BooleanPref) = pref match {
     case ShowNotificationPref => ...
     case ...
  }

  def set(pref: BooleanPref, value: Boolean): Unit = pref match {
     case ShowNotificationPref => ...
     case ...
  }
}

如果setget 实现以某种方式分解,仍有改进的空间。不知道这个细节,很难说。

您还可以考虑通过检查BooleanPref 子类型来生成不同案例的宏,但同样需要有关特定案例的更多信息。

【讨论】:

    猜你喜欢
    • 2011-05-31
    • 2017-09-07
    • 1970-01-01
    • 1970-01-01
    • 2014-10-03
    • 1970-01-01
    • 2015-09-30
    • 2012-06-09
    • 1970-01-01
    相关资源
    最近更新 更多