假设以下一对类:
class A(arg:String)
class B(argList:Vector[String]) extends A(argList.first)
我希望能够在为基类构造函数提供第一个元素之前检查argList
是否为空。不幸的是,将该检查置于B
的默认构造函数中(例如通过require
,如图所示here)为时已晚,因为需要首先调用基类的构造函数。
这可能是一个更普遍的OOP问题,但解决方案可能是Scala特定的。
答案 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]