为 class 构造引用特征之外的抽象类型

Referring to abstract type outside of trait for class construction

前提:

我想将实例化 class 所需的信息与 "run" class 所需的信息分开。但是,"run" 和 class 所需的信息可能不同于 class 和 class。于是,我把class想象成"has"具体的资料给运行吧,两个一起去。

这是我的代码示例:

trait Machine {
  type Params <: BaseParams

  def start(machineParams: Params): Unit
}

trait BaseParams {
  def speed: Int
  def power: Int
}

class FlyingMachine() extends Machine {
  type Params = FlyingParams

  override def start(machineParams: Params): Unit = {
    println(s"I'm flying with $machineParams")
  }
}

trait FlyingParams extends BaseParams {
  def height: Int
}


abstract class MachineOwner{

  val machine: Machine

  def params: machine.Params

  def startMachine(): Unit = {
    machine.start(params)
  }
}

编译通过,测试通过,我很高兴。

问题:我正在使用 val machine: Machine 来定义 def params: machine.Params。有人告诉我将其设为 def 以让实施者拥有更多自由。如果我这样做,我就不能再参考 machine.Params

此时,我不知道如何继续。我一直在想,如果这应该是 def 而绝对不是 val,那么我的架构是错误的。

所以

  1. 考虑到我提出的前提,我解决这个问题的方法是否错误?
  2. 如果没有错,在 MachineOwner class 中使用 def 而不是 val 是否仍然可以实现此目的?

编辑 鉴于 Alexey Romanov 的回答,代码的最后一位将如下所示

abstract class MachineOwner{

  type Params1 <: BaseParams

  def machine: Machine { type Params = Params1 }

  def params: Params1

  def startMachine(): Unit = {
    machine.start(params)
  }
}

class FlyingMachineOwner(
  machine: FlyingMachine
) extends MachineOwner {

  override type Params1 = FlyingParams

  override def params = FlyingParams(1,1,1)
}

但这不会编译,因为它需要专门针对 def machine: Machine { type Params = Params1 } 的覆盖。如何定义它?

如果不知道所需的语义,确实无法回答。

如果 MachineOwner 应该拥有一台机器,那么 "to make this a def to let the implementer have more freedom" 是个糟糕的建议:它提供的自由恰恰是 return 不同机器从不同调用 def machine 而不是保留对它给出的机器的引用。

如果它应该有多台机器,它们都应该具有相同的 Params 类型吗?然后你会做类似

的事情
abstract class MachineOwner{

  type Params1 <: BaseParams

  def machine: Machine { type Params = Params1 }

  def params: Params1

  def startMachine(): Unit = {
    machine.start(params)
  }
}

或者,如果不是,那么您需要再次进行不同的设计,也许 def params(machine: Machine): machine.Params。等等等等

对于编辑:您可以

class FlyingMachineOwner(
  _machine: FlyingMachine
) extends MachineOwner {

  override type Params1 = FlyingParams

  override def params = FlyingParams(1,1,1)

  override def machine = _machine
}

但与使用类型参数得到的结果相比,它确实显得不必要地复杂。