参数化比例特征

Parametrising Scala trait

免责声明:这个问题不是关于我是否应该这样做或它是否是一个好的设计,也不是任何相关的推理。问题是我该怎么做。我稍后解释为什么只是为了澄清。


我可以参数化 Scala 特征吗?我知道他们不能有构造函数参数 - 有不同的方法吗?对于类似的东西(当然这只是一个例子)

case class MyMachine(myDouble: Double) {
    def methodEveryMachineHas(): Double = 2 * myDouble
}

trait Drivable {
    this: MyMachine =>

    def drive(x: Double): Double = HowToDriveFunction(x) * myDouble

}

object HowToDriveFunction extends (Double => Double) {
    def apply(x:Double): Double = x + 6.0
}

val myMachine1 = new MyMachine(3.0)
myMachine1.methodEveryMachineHas // 6.0
myMachine1.drive(4.0) // error

val myMachine2 = new MyMachine(3.0) with Drivable
myClass1.methodEveryMachineHas // 6.0
myClass1.drive(4.0) // 30.0 = (4.0 + 6.0) * 3.0

如何将 HowToDriveFunction 传递给 drive

为什么我想要这个

将逻辑上不同的事物表示为程序上的不同事物,使代码有意义

函数应该固定锚定在对象(=实例化class)本身。因此,我希望它在创作过程中被赋予。然而,并非所有 MyMachine 都应该具有驱动能力。

想象MyMachine是一台机器,Drivable说它是可驱动的——如果某物不能按逻辑驱动,我认为它在技术上也不应该能够驱动,因此特征。但我仍然需要解释(通过 HowToDriveFunction)这台特定机器(可能是汽车或飞机)的驱动是如何工作的。但是,我为什么要能够解释每台机器是如何驱动的呢?这是没有意义的。我只想向那些会开车的人解释。因此,我想将 HowToDriveFunction 赋予特征(表示机器可以驱动,因此首先应该能够驱动)。 如何驾驶工作不是能力(=特质),而是对机制的描述,我认为应该用功能来表示。如果它在逻辑上是不同的,那么如果用不同的编程结构来表示就更好了。

当然,我实际的东西与机器等无关 - 这只是一个例子。

如果我的功能是通过另一个特征给出的,我可以写

trait HowToDriveFunction {
    this: Drivable =>
    ???
}

确保只有 Drivable 的人才能得到 HowToDriveFunction 的子 class,但这对我来说并不那么漂亮,原因已解释。

正在关注 "composition over inheritance"

最后但并非最不重要的一点是,我认为拥有 composition over inheritance 是件好事,因为我觉得它更容易推理代码。

我不确定我是否完全理解这个问题,但它似乎可以归结为

How do I pass HowToDriveFunction to drive?

并且能够定义 MyMachine 而无需驱动。

为此,您只需在 Drivable 中定义一个抽象成员。

case class MyMachine(myDouble: Double) {
  def methodEveryMachineHas: Double = 2 * myDouble
}

trait Drivable {
  this: MyMachine =>

  protected def driveFunction: Double => Double

  def drive(x: Double): Double = driveFunction(x) * myDouble
}

object HowToDriveFunction extends (Double => Double) {
  def apply(x: Double): Double = x + 6.0
}

val myMachine1 = new MyMachine(3.0)
myMachine1.methodEveryMachineHas // 6.0
myMachine1.drive(4.0) // error

val myMachine2 = new MyMachine(3.0) with Drivable { 
  val driveFunction = HowToDriveFunction
}
myMachine2.methodEveryMachineHas // 6.0
myMachine2.drive(4.0) // 30.0 = (4.0 + 6.0) * 3.0