通常,在构造时抛出异常并不是一件很礼貌的事情,但是我不确定在尝试对case类值施加约束时如何避免这种情况。
举例来说,我需要代表一个范围,并且两个边界都必须为正。立即实施是:
case class Range(from: Int, to: Int)
但是,这不能确保from
和to
都为正,也不能to
大于from
。
我的第一个本能是按以下方式实现它:
case class Range(from: Int, to: Int) {
require(from >= 0)
require(to >= 0)
require(to >= from)
}
但是,这使Range
的构造函数不安全。
是否存在一种通用的模式来保持案例类的易用性,强制执行值约束并避免引发异常?
这是非常主观的,但是我会尝试的。
这取决于您的班级的构造方式。在内部代码中随便使用一个简单的实用程序范围类的情况下,任何使用它的程序员都应该意识到,给范围错误的值可能会导致奇怪的结果。您可以假定对类的合理使用确实不会遇到此问题,并且在这些罕见的情况下引发异常可能不是一个不好的做法,以表明有人真的被搞砸了。如果从上下文可以明显看出应该将什么价值观提供给班级,我认为如果人们不能满足这些理智的期望就抛出异常并不是特别不好的口味。
将此与有时在Scala中仍然发生的NullPointerException
s或ArithmethicException
s的行为进行比较。有时,面对足够的“精神错乱”时,进行防御性编程已经不合理了。
另一方面,如果您的类被值填充,则您对它们的控制较少,即它们是用户输入的直接结果,您只需要简单地对构造进行更多控制。使用返回Option
或的函数创建伴随对象Either
:
object Range {
def createSafe(from: Int, to: Int): Option[Range] = {
if(from >= 0 && to >= 0 && to >= from)
Some(Range(from, to))
else
None
}
}
然后,您甚至可以通过覆盖apply
其他建议的答案,甚至在案例类的实例化中重用验证逻辑。
object Range {
def createSafe ...
def apply(from: Int, to: Int): Range = {
createSafe(from, to).getOrElse(throw new IllegalArgumentException(...))
}
}
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句