为 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
,那么我的架构是错误的。
所以
- 考虑到我提出的前提,我解决这个问题的方法是否错误?
- 如果没有错,在
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
}
但与使用类型参数得到的结果相比,它确实显得不必要地复杂。
前提:
我想将实例化 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
,那么我的架构是错误的。
所以
- 考虑到我提出的前提,我解决这个问题的方法是否错误?
- 如果没有错,在
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
}
但与使用类型参数得到的结果相比,它确实显得不必要地复杂。