检查Scala中的派生类参数

时间:2015-11-02 11:18:19

标签: scala inheritance constructor

假设以下一对类:

class A(arg:String)

class B(argList:Vector[String]) extends A(argList.first)

我希望能够在为基类构造函数提供第一个元素之前检查argList是否为空。不幸的是,将该检查置于B的默认构造函数中(例如通过require,如图所示here)为时已晚,因为需要首先调用基类的构造函数。

这可能是一个更普遍的OOP问题,但解决方案可能是Scala特定的。

3 个答案:

答案 0 :(得分:4)

如果argList为空,您希望通过什么?无论如何,您只需使用以下内容:

class B(argList:Vector[String]) extends A(argList.headOption.getOrElse("your default string here")

答案 1 :(得分:4)

解决这个问题的一种方法是通过伴侣对象。您可以将B的构造函数标记为私有,以确保没有人可以绕过检查,然后向预先检查输入值的伴随对象添加合适的apply方法:

class A(arg:String)

class B private(argList:Vector[String]) extends A(argList.head)

object B {
  def apply(argList:Vector[String]): B = argList.headOption.map(_ => new B(argList)).getOrElse(throw new RuntimeException("Oops"))
}

用法示例:

scala> B(Vector("foo", "bar"))
res2: B = B@328e9109

scala> B(Vector())
java.lang.RuntimeException: Oops
    at B$$anonfun$apply$2.apply(<console>:24)
    ...

请注意,为了简单起见,我只是在处理错误数据时抛出异常,但可能会尝试其他方式来处理这种情况(@ Zoltan的默认值是这样的答案之一)。

答案 2 :(得分:1)

这就是为什么在大多数地方构造函数都被工厂对象替换。在Scala中,使用伴侣对象作为这样的工具是惯用的。

class A(arg: String)

abstract class B(arg: String) extends A(arg) {
  def argList: IndexedSeq[String]
}

object B {
  case object Empty extends B("") {
    def argList = IndexedSeq.empty
  }
  case class NonEmpty private[B](argList: Vector[String]) extends B(argList.head)

  def apply(argList: Vector[String]) =
    if (argList.isEmpty) Empty else NonEmpty(argList)

  def unapplySeq(b:B): Option[IndexedSeq[String]] = b match {
    case Empty ⇒ Some(IndexedSeq.empty)
    case NonEmpty(args) ⇒ Some(args)
  }
}

你可以验证

B(Vector()) == B.Empty

B(Vector("x", "y")).isInstanceOf[B.NonEmpty]