参数化Scala特征

时间:2016-10-10 16:03:05

标签: scala traits

免责声明:这个问题不是关于我是否应该这样做,或者它是一个好的设计还是任何相关的推理。问题是如何做到这一点。我在后面解释原因只是为了澄清。

我可以参数化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

为什么我要这个

将逻辑上不同的东西表示为程序化的不同东西,使代码变得有意义

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

想象一下MyMachine成为一台机器,并Drivable说它是可驾驶的 - 如果某些东西不能通过逻辑驱动,我认为它也不应该在技术上能够驱动,因此特点。但是我仍然需要解释(通过HowToDriveFunction)这种特定机器(可能是汽车或飞机)的驾驶方式。但是,为什么我能够解释每台机器如何驾驶?这是没有意义的。我只想向那些可以开车的人解释一下。因此,我想给HowToDriveFunction提供特性(表示机器可以驱动,因此应该能够首先驱动)。 如何驾驶工作不是一种能力(=特质),而是对力学的描述,应该由我认为的一个功能来表示。如果它在逻辑上是不同的,那么如果用不同的编程结构表示它会很好。

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

如果我的功能是通过其他特性给出的,我可以写

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

确保只有那些Drivable获得HowToDriveFunction的子类,但由于原因的解释,这对我来说似乎并不那么美好。

以下"组成而非继承"

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

1 个答案:

答案 0 :(得分:3)

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

  

如何将HowToDriveFunction传递给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