Scala中的可选布尔参数

Scala中的可选布尔参数,scala,Scala,我最近一直在开发基于ApachePOI功能的DSL风格的库包装器,并面临着一个我似乎不是很好的解决方案的挑战 该库的目标之一是为用户提供将电子表格模型构建为不可变对象集合的能力,即 val headerStyle=CellStyle(fillPattern=CellFill.Solid,fillForegroundColor=Color.AquaMarine,font=font(bold=true)) val italicStyle=CellStyle(font=font(italic=true

我最近一直在开发基于ApachePOI功能的DSL风格的库包装器,并面临着一个我似乎不是很好的解决方案的挑战

该库的目标之一是为用户提供将电子表格模型构建为不可变对象集合的能力,即

val headerStyle=CellStyle(fillPattern=CellFill.Solid,fillForegroundColor=Color.AquaMarine,font=font(bold=true))

val italicStyle=CellStyle(font=font(italic=true))

根据以下假设:

  • 用户可以选择指定任何参数(也就是说,您可以创建不带参数的
    CellStyle
    ,也可以使用明确指定的参数的完整列表)
  • 如果用户未明确指定参数,则认为该参数未定义,将使用默认环境值(我们转换为的格式的默认值)
第二点很重要,因为我想将此数据模型转换为多种格式,即Excel中的默认字体不必与HTML浏览器中的默认字体相同(如果用户没有明确定义字体系列,我希望他使用这些默认字体查看数据)

为了处理需求,我使用了这里描述的空模式的变体:这里也建议使用(下面是一个简化的示例)

由于null只在伴生对象内部使用,并且非常本地化,为了解决方案的简单性,我决定接受null牺牲。该模式适用于所有引用类

但是,对于Scala基元类型,不能指定wrappers null。这是一个特别大的问题,我有效地考虑了3个状态(真,假和未定义)。为了提供用户仍然能够编写
bold=true
的界面,我决定使用接受空值的Java包装器

object ModelObject {
  def apply(boolParam : java.lang.Boolean = null) : ModelObject = ModelObject(
    boolParam = Option(boolParam).map(_.booleanValue)
  )
}
case class ModelObject private(boolParam : Option[Boolean])
然而,这是不对的,我一直在想是否有更好的方法来解决这个问题。我一直在考虑定义联合类型(使用其他对象表示未定义的值):,但是,由于未定义状态不应该显式地用于IDE向用户公开的参数类型,这将非常容易混淆(理想情况下,我希望它是布尔型的)

有没有更好的办法解决这个问题

进一步资料:

  • 更多DSL API示例:
  • 完整类的示例实现:

您可以使用我在这里描述的模式的变体:

总之,您可以使用一些helper泛型类来表示可选参数(很像
选项

您可以这样简单地使用它:

scala>case class ModelObject(boolParam: OptArg[Boolean] = NoArg)
defined class ModelObject

scala> ModelObject(true)
res12: ModelObject = ModelObject(SomeArg(true))

scala> ModelObject()
res13: ModelObject = ModelObject(NoArg)    
但是,正如您所看到的,
OptArg
现在泄漏在
ModelObject
类本身中(
boolParam
被键入为
Option[Boolean]
)。 解决这个问题(如果对您很重要)只需要像您自己一样定义一个单独的工厂:

scala> :paste
// Entering paste mode (ctrl-D to finish)
case class ModelObject private(boolParam: Option[Boolean])
object ModelObject {
  def apply(boolParam: OptArg[Boolean] = NoArg): ModelObject = new ModelObject(
    boolParam = boolParam.toOption
  )
}
// Exiting paste mode, now interpreting.
defined class ModelObject
defined module ModelObject

scala> ModelObject(true)
res22: ModelObject = ModelObject(Some(true))

scala> ModelObject()
res23: ModelObject = ModelObject(None)

UPDATE与@drexin所示的简单定义几个重载的
apply
方法相比,使用此模式的优势在于,在后一种情况下,重载的数量随着参数的数量快速增长(2^N)。如果
ModelObject
有4个参数,这意味着需要手动写入16个重载!

您可以使用我在这里描述的模式的变体:

总之,您可以使用一些helper泛型类来表示可选参数(很像
选项

您可以这样简单地使用它:

scala>case class ModelObject(boolParam: OptArg[Boolean] = NoArg)
defined class ModelObject

scala> ModelObject(true)
res12: ModelObject = ModelObject(SomeArg(true))

scala> ModelObject()
res13: ModelObject = ModelObject(NoArg)    
但是,正如您所看到的,
OptArg
现在泄漏在
ModelObject
类本身中(
boolParam
被键入为
Option[Boolean]
)。 解决这个问题(如果对您很重要)只需要像您自己一样定义一个单独的工厂:

scala> :paste
// Entering paste mode (ctrl-D to finish)
case class ModelObject private(boolParam: Option[Boolean])
object ModelObject {
  def apply(boolParam: OptArg[Boolean] = NoArg): ModelObject = new ModelObject(
    boolParam = boolParam.toOption
  )
}
// Exiting paste mode, now interpreting.
defined class ModelObject
defined module ModelObject

scala> ModelObject(true)
res22: ModelObject = ModelObject(Some(true))

scala> ModelObject()
res23: ModelObject = ModelObject(None)

UPDATE与@drexin所示的简单定义几个重载的
apply
方法相比,使用此模式的优势在于,在后一种情况下,重载的数量随着参数的数量快速增长(2^N)。如果
ModelObject
有4个参数,这意味着需要手动写入16个重载!

您可以使用我在这里描述的模式的变体:

总之,您可以使用一些helper泛型类来表示可选参数(很像
选项

您可以这样简单地使用它:

scala>case class ModelObject(boolParam: OptArg[Boolean] = NoArg)
defined class ModelObject

scala> ModelObject(true)
res12: ModelObject = ModelObject(SomeArg(true))

scala> ModelObject()
res13: ModelObject = ModelObject(NoArg)    
但是,正如您所看到的,
OptArg
现在泄漏在
ModelObject
类本身中(
boolParam
被键入为
Option[Boolean]
)。 解决这个问题(如果对您很重要)只需要像您自己一样定义一个单独的工厂:

scala> :paste
// Entering paste mode (ctrl-D to finish)
case class ModelObject private(boolParam: Option[Boolean])
object ModelObject {
  def apply(boolParam: OptArg[Boolean] = NoArg): ModelObject = new ModelObject(
    boolParam = boolParam.toOption
  )
}
// Exiting paste mode, now interpreting.
defined class ModelObject
defined module ModelObject

scala> ModelObject(true)
res22: ModelObject = ModelObject(Some(true))

scala> ModelObject()
res23: ModelObject = ModelObject(None)

UPDATE与@drexin所示的简单定义几个重载的
apply
方法相比,使用此模式的优势在于,在后一种情况下,重载的数量随着参数的数量快速增长(2^N)。如果
ModelObject
有4个参数,这意味着需要手动写入16个重载!

您可以使用我在这里描述的模式的变体:

总之,您可以使用一些helper泛型类来表示可选参数(很像
选项

您可以这样简单地使用它:

scala>case class ModelObject(boolParam: OptArg[Boolean] = NoArg)
defined class ModelObject

scala> ModelObject(true)
res12: ModelObject = ModelObject(SomeArg(true))

scala> ModelObject()
res13: ModelObject = ModelObject(NoArg)    
但是,正如您所看到的,
OptArg
现在泄漏在
ModelObject
类本身中(
boolParam
被键入为
Option[Boolean]
)。 解决这个问题(如果对您很重要)只需要像您自己一样定义一个单独的工厂:

scala> :paste
// Entering paste mode (ctrl-D to finish)
case class ModelObject private(boolParam: Option[Boolean])
object ModelObject {
  def apply(boolParam: OptArg[Boolean] = NoArg): ModelObject = new ModelObject(
    boolParam = boolParam.toOption
  )
}
// Exiting paste mode, now interpreting.
defined class ModelObject
defined module ModelObject

scala> ModelObject(true)
res22: ModelObject = ModelObject(Some(true))

scala> ModelObject()
res23: ModelObject = ModelObject(None)
更新使用此模式的优点,与简单地定义几个重载的
apply
方法相比