在抽象 Scala 中实现加法 class

Implement addition in abstract Scala class

我有以下摘要 class 及其两个子class:

abstract class BoundedNumber(val lowerBound: Double,
                             val upperBound: Double,
                             val value: Double) {
  require(value >= lowerBound && value <= upperBound)
}

final case class Percentage(override val value: Double)
  extends BoundedNumber(0, 100, value)

final case class Probability(override val value: Double)
  extends BoundedNumber(0, 1, value)

我能否以某种方式在 BoundedNumber 中实现 "generic" 添加,即使它是抽象的且无法实例化?

abstract class BoundedNumber(val lowerBound: Double,
                             val upperBound: Double,
                             val value: Double) {
  def +(that: BoundedNumber): BoundedNumber = {
    require(this.getClass == that.getClass)
    // This of course won't compile:
    new BoundedNumber(lowerBound, upperBound, value + that.value)
  }
}

或者我是否必须(双关语)在两个子classes 中实现加法从而重复代码?

您不能实例化抽象 class,但是您可以在 BoundedNumber 中指定一个抽象方法,用所需的更新值创建新实例。

  abstract class BoundedNumber(val lowerBound: Double,
                               val upperBound: Double,
                               val value: Double) {
    require(value >= lowerBound && value <= upperBound)

    def copy(value: Double): BoundedNumber

    def +(that: BoundedNumber): BoundedNumber = {
      require(this.getClass == that.getClass)
      that.copy(value + that.value)
    }
  }

  final case class Percentage(override val value: Double) extends BoundedNumber(0, 100, value) {
    override def copy(value: Double): BoundedNumber =  Percentage(value)
  }

  final case class Probability(override val value: Double) extends BoundedNumber(0, 1, value){
    override def copy(value: Double): BoundedNumber = Probability(value)
  }

在抽象 class 和 return 中创建一个具体的 class :

abstract class BoundedNumber(val lowerBound: Double,
                             val upperBound: Double,
                             val value: Double) {

  class ConcreteBoundedNumber(lowerBound: Double,
                              upperBound: Double,
                              value: Double) extends BoundedNumber(lowerBound, upperBound, value)

  def +(that: BoundedNumber): BoundedNumber = {
    require(this.getClass == that.getClass)

    new ConcreteBoundedNumber(lowerBound, upperBound, value + that.value)
  }
}

这给出了 + 的通用实现,无需向子 class 中添加任何代码。

如果您的目标是编译时类型安全,即 + 的两个操作数必须具有相同的具体类型并且 + 也 returns 具有相同的具体类型,您可以声明一个抽象类型和构造函数,它将由每个具体的 subclass 实现。 + 然后可以在摘要中定义 class:

abstract class BoundedNumber(val lowerBound: Double, val upperBound: Double, val value: Double) {
    require(value >= lowerBound && value <= upperBound)
    type Self <: BoundedNumber
    def make(value: Double): Self

    def +(that: Self): Self = make(value + that.value)
}

final case class Percentage(override val value: Double) extends BoundedNumber(0, 100, value) {
    type Self = Percentage
    def make(value: Double): Self = Percentage(value)
}

final case class Probability(override val value: Double) extends BoundedNumber(0, 1, value) {
    type Self = Probability
    def make(value: Double): Self = Probability(value)
}

现在编译器将正确推断 Percentage+ 的参数必须是 Percentage 类型并且结果将是 Percentage 类型。